您好,登錄后才能下訂單哦!
本篇內容主要講解“Go語言協程處理數據問題怎么解決”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Go語言協程處理數據問題怎么解決”吧!
當然第一個想到可能是采用協程處理循環里面要查詢的數據
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)) }
運行上述代碼,結果: "數據:[]",這是為什么呢?主要是協程處理業務需要時間,循環提前結束,所以才會出現這樣的結果,該怎么讓所有結果都處理結束才輸出結果呢?
此方法就是等待組進行多個任務的同步,等待組可以保證在并發環境中完成指定數量的任務
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(),我們需要接收,使用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語言協程處理數據問題怎么解決”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。