中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Go語言協程處理數據問題怎么解決

發布時間:2023-02-25 10:54:17 來源:億速云 閱讀:137 作者:iii 欄目:開發技術

本篇內容主要講解“Go語言協程處理數據問題怎么解決”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Go語言協程處理數據問題怎么解決”吧!

一、Goroutine

當然第一個想到可能是采用協程處理循環里面要查詢的數據

type Card struct {
	Name    string  `json:"name"`
	Balance float64 `json:"balance"`
}
func main() {
	// 獲取卡列表數據
	list := getList()
	var data = make([]Card, 0, len(list))
	for _, val := range list {
		go func(card Card) {
			// 查詢業務,將值加入該記錄中
			var balance = getBalance()
			data = append(data, Card{
				Name:    card.Name,
				Balance: balance,
			})
		}(val)
	}
	log.Printf("數據:%+v", data)
}
// 獲取數據列表
func getList() []Card {
	var list = make([]Card, 0)
	for i := 0; i < 10000; i++ {
		list = append(list, Card{
			Name: "卡-" + strconv.Itoa(i+1),
		})
	}
	return list
}
// 獲取余額
func getBalance() float64 {
	time.Sleep(time.Millisecond * 100)
	return float64(rand.Int63n(1000))
}

運行上述代碼,結果: "數據:[]",這是為什么呢?主要是協程處理業務需要時間,循環提前結束,所以才會出現這樣的結果,該怎么讓所有結果都處理結束才輸出結果呢?

二、sync.WaitGroup

此方法就是等待組進行多個任務的同步,等待組可以保證在并發環境中完成指定數量的任務

func main() {
	list := getList() // 獲取卡列表數據
	var data = make([]Card, 0, len(list))
	var wg sync.WaitGroup // 聲明一個等待組
	for _, val := range list {
		wg.Add(1) // 每一個任務開始時,將等待組增加1
		go func(card Card) {
			defer wg.Done() // 使用defer, 表示函數完成時將等待組值減1
			// 查詢業務,休眠100微妙,將值加入該記錄中
			var balance = getBalance()
			data = append(data, Card{
				Name:    card.Name,
				Balance: balance,
			})
		}(val)
	}
	wg.Wait() // 等待所有任務完成
	log.Printf("數據:%+v", data)
}

運行結果會輸出所有數據,但細心的我們會發現,這個時候數據的順序是亂的,這個也符合業務需求,該怎么進一步改良呢?

三、數據排序

上面講到協程處理之后的額數據是無序的,這里我們知道數據跳數,直接初始化一個len和cap等于len(list)的空間,將之前append到data的數據改成通過下標復制,這樣輸出的數據就是list的數據順序。

func main() {
	list := getList() // 獲取卡列表數據
	var data = make([]Card, len(list), len(list))
	var wg sync.WaitGroup // 聲明一個等待組
	for k, val := range list {
		wg.Add(1) // 每一個任務開始時,將等待組增加1
		go func(k int, card Card) {
			defer wg.Done() // 使用defer, 表示函數完成時將等待組值減1
			// 查詢業務,休眠100微妙,將值加入該記錄中
			var balance = getBalance()
			data[k] = Card{
				Name:    card.Name,
				Balance: balance,
			}
		}(k, val)
	}
	wg.Wait() // 等待所有任務完成
	log.Printf("數據:%+v", data)
}

運行上述代碼,雖然可以獲取到想要的數據排序,但下次下載數據較多,開的協程過多,勢必導致資源開銷過大,帶來一系列問題,那怎么優化限制協程個數呢?

四、限制協程數

大家都知道協程過多,自然消耗過多資源,可能導致其他問題;這里我們借助chan限制協程個數

// 限制100個協程
type pool struct {
	queue chan int
	wg    *sync.WaitGroup
}
func main() {
	list := getList() // 獲取卡列表數據
	var data = make([]Card, len(list), len(list))
	var gl = &pool{queue: make(chan int, 500), wg: &sync.WaitGroup{}} // 顯示協程數最大500個
	for k, val := range list {
		gl.queue <- 1 // 每一個任務開始時, chan輸入1個
		gl.wg.Add(1)  // 每一個任務開始時,將等待組增加1
		go func(k int, card Card) {
			defer func() {
				<-gl.queue   // 完成時chan取出1個
				gl.wg.Done() // 完成時將等待組值減1
			}()
			// 查詢業務,休眠100微妙,將值加入該記錄中
			var balance = getBalance()
			data[k] = Card{
				Name:    card.Name,
				Balance: balance,
			}
		}(k, val)
	}
	gl.wg.Wait() // 等待所有任務完成
	log.Printf("數據:%+v", data)
}

通過使用chan,可以自己定義可協程最大數;現在看起來沒有什么問題,但如果協程獲取數據panic,會導致整個程序崩潰。

五、協程Panic處理

針對協程的panic(),我們需要接收,使用recover處理

func main() {
	list := getList() // 獲取卡列表數據
	var data = make([]Card, len(list), len(list))
	var gl = &pool{queue: make(chan int, 500), wg: &sync.WaitGroup{}} // 顯示協程數最大500個
	for k, val := range list {
		gl.queue <- 1 // 每一個任務開始時, chan輸入1個
		gl.wg.Add(1)  // 每一個任務開始時,將等待組增加1
		go func(k int, card Card) {
			// 解決協程panic,不至于程序崩潰
			defer func() {
				recover()
			}()
			defer func() {
				<-gl.queue   // 完成時chan取出1個
				gl.wg.Done() // 完成時將等待組值減1
			}()
			// 查詢業務,休眠100微妙,將值加入該記錄中
			var balance = getBalance()
			data[k] = Card{
				Name:    card.Name,
				Balance: balance,
			}
		}(k, val)
	}
	gl.wg.Wait() // 等待所有任務完成
	log.Printf("數據:%+v", data)
}
// 獲取余額
func getBalance() float64 {
	panic("獲取余額panic")
	time.Sleep(time.Millisecond * 100)
	return float64(rand.Int63n(1000))
}

在協程中使用defer recover();這樣協程拋出來的panic被接受,不會導致程序奔潰。

到此,相信大家對“Go語言協程處理數據問題怎么解決”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

益阳市| 洛宁县| 任丘市| 通江县| 水城县| 兴文县| 商城县| 肇源县| 澄城县| 祁门县| 青海省| 濮阳县| 乌审旗| 紫金县| 东丽区| 泾川县| 象山县| 阳曲县| 冷水江市| 武清区| 平舆县| 大姚县| 兴城市| 龙州县| 清徐县| 手游| 蒙城县| 沂源县| 淄博市| 霞浦县| 蓬莱市| 本溪市| 江华| 阿勒泰市| 东丰县| 新竹县| 嵩明县| 济阳县| 唐海县| 阳谷县| 昌平区|