最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go語言協(xié)程處理數(shù)據(jù)有哪些問題

 更新時(shí)間:2023年02月20日 09:59:44   作者:尋找09之夏  
協(xié)程(coroutine)是Go語言中的輕量級(jí)線程實(shí)現(xiàn),由Go運(yùn)行時(shí)(runtime)管理。本文為大家詳細(xì)介紹了Go中的協(xié)程,協(xié)程不需要搶占式調(diào)度,可以有效提高線程的任務(wù)并發(fā)性,而避免多線程的缺點(diǎn)

前言

我們?cè)陂_發(fā)后臺(tái)項(xiàng)目常常會(huì)遇到一個(gè)情況,功能模塊列表數(shù)據(jù)導(dǎo)出Excel功能,但列表中某個(gè)字段無法通過Sql聯(lián)表查詢,且一次性查詢?cè)倨?duì)也不方便;此時(shí)對(duì)列表數(shù)據(jù)循環(huán),再一個(gè)個(gè)查詢結(jié)果加入列表,勢(shì)必需要很長(zhǎng)的時(shí)間,我們?cè)撛趺床拍芴嵘螺d速度呢? (這里采用Go開發(fā)服務(wù)端)

一、Goroutine

當(dāng)然第一個(gè)想到可能是采用協(xié)程處理循環(huán)里面要查詢的數(shù)據(jù)

type Card struct {
	Name    string  `json:"name"`
	Balance float64 `json:"balance"`
}
func main() {
	// 獲取卡列表數(shù)據(jù)
	list := getList()
	var data = make([]Card, 0, len(list))
	for _, val := range list {
		go func(card Card) {
			// 查詢業(yè)務(wù),將值加入該記錄中
			var balance = getBalance()
			data = append(data, Card{
				Name:    card.Name,
				Balance: balance,
			})
		}(val)
	}
	log.Printf("數(shù)據(jù):%+v", data)
}
// 獲取數(shù)據(jù)列表
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))
}

運(yùn)行上述代碼,結(jié)果: "數(shù)據(jù):[]",這是為什么呢?主要是協(xié)程處理業(yè)務(wù)需要時(shí)間,循環(huán)提前結(jié)束,所以才會(huì)出現(xiàn)這樣的結(jié)果,該怎么讓所有結(jié)果都處理結(jié)束才輸出結(jié)果呢?

二、sync.WaitGroup

此方法就是等待組進(jìn)行多個(gè)任務(wù)的同步,等待組可以保證在并發(fā)環(huán)境中完成指定數(shù)量的任務(wù)

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

運(yùn)行結(jié)果會(huì)輸出所有數(shù)據(jù),但細(xì)心的我們會(huì)發(fā)現(xiàn),這個(gè)時(shí)候數(shù)據(jù)的順序是亂的,這個(gè)也符合業(yè)務(wù)需求,該怎么進(jìn)一步改良呢?

三、數(shù)據(jù)排序

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

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

運(yùn)行上述代碼,雖然可以獲取到想要的數(shù)據(jù)排序,但下次下載數(shù)據(jù)較多,開的協(xié)程過多,勢(shì)必導(dǎo)致資源開銷過大,帶來一系列問題,那怎么優(yōu)化限制協(xié)程個(gè)數(shù)呢?

四、限制協(xié)程數(shù)

大家都知道協(xié)程過多,自然消耗過多資源,可能導(dǎo)致其他問題;這里我們借助chan限制協(xié)程個(gè)數(shù)

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

通過使用chan,可以自己定義可協(xié)程最大數(shù);現(xiàn)在看起來沒有什么問題,但如果協(xié)程獲取數(shù)據(jù)panic,會(huì)導(dǎo)致整個(gè)程序崩潰。

五、協(xié)程Panic處理

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

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

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

總結(jié)

協(xié)程在處理數(shù)據(jù)數(shù)據(jù)通過使用更多資源提升效率協(xié)程過多會(huì)暫用其他服務(wù)資源,我們使用協(xié)程過多時(shí)需要考慮限制協(xié)程中panic需要處理,不然會(huì)導(dǎo)致程序崩潰

到此這篇關(guān)于Go語言協(xié)程處理數(shù)據(jù)有哪些問題的文章就介紹到這了,更多相關(guān)Go協(xié)程處理數(shù)據(jù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go 通過結(jié)構(gòu)struct實(shí)現(xiàn)接口interface的問題

    Go 通過結(jié)構(gòu)struct實(shí)現(xiàn)接口interface的問題

    這篇文章主要介紹了Go 通過結(jié)構(gòu)struct實(shí)現(xiàn)接口interface的問題,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-10-10
  • Golang壓縮Jpeg圖片和PNG圖片的操作

    Golang壓縮Jpeg圖片和PNG圖片的操作

    這篇文章主要介紹了Golang壓縮Jpeg圖片和PNG圖片的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go select 死鎖的一個(gè)細(xì)節(jié)

    Go select 死鎖的一個(gè)細(xì)節(jié)

    這篇文章主要給大家分享的是Go select 死鎖的一個(gè)細(xì)節(jié),文章先是對(duì)主題提出問題,然后展開內(nèi)容,感興趣的小伙伴可以借鑒一下,希望對(duì)你有所幫助
    2021-10-10
  • logrus hook輸出日志到本地磁盤的操作

    logrus hook輸出日志到本地磁盤的操作

    這篇文章主要介紹了logrus hook輸出日志到本地磁盤的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11
  • 關(guān)于升級(jí)go1.18的goland問題詳解

    關(guān)于升級(jí)go1.18的goland問題詳解

    作為一個(gè)go語言程序員,覺得自己有義務(wù)為go新手開一條更簡(jiǎn)單便捷的上手之路,下面這篇文章主要給大家介紹了關(guān)于升級(jí)go1.18的goland問題的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • Go 簡(jiǎn)單實(shí)現(xiàn)多租戶數(shù)據(jù)庫隔離

    Go 簡(jiǎn)單實(shí)現(xiàn)多租戶數(shù)據(jù)庫隔離

    本文主要介紹了Go 簡(jiǎn)單實(shí)現(xiàn)多租戶數(shù)據(jù)庫隔離,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • 解決Golang中g(shù)oroutine執(zhí)行速度的問題

    解決Golang中g(shù)oroutine執(zhí)行速度的問題

    這篇文章主要介紹了解決Golang中g(shù)oroutine執(zhí)行速度的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Golang中重復(fù)錯(cuò)誤處理的優(yōu)化方法

    Golang中重復(fù)錯(cuò)誤處理的優(yōu)化方法

    這篇文章主要給大家介紹了關(guān)于Golang中重復(fù)錯(cuò)誤處理優(yōu)化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Golang具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 淺談golang類型斷言,失敗類型斷言返回值問題

    淺談golang類型斷言,失敗類型斷言返回值問題

    這篇文章主要介紹了淺談golang類型斷言,失敗類型斷言返回值問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go語言中錯(cuò)誤處理的方式總結(jié)

    Go語言中錯(cuò)誤處理的方式總結(jié)

    這篇文章會(huì)結(jié)合?errors?中的函數(shù),來討論一下?Go?中常見的?error?使用方式,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,需要的可以了解一下
    2023-07-07

最新評(píng)論

曲松县| 胶州市| 台北县| 汤阴县| 通化市| 莆田市| 南部县| 新宁县| 武鸣县| 宁国市| 印江| 双柏县| 祥云县| 文登市| 尤溪县| 井陉县| 岚皋县| 富宁县| 建始县| 农安县| 美姑县| 灌云县| 阳城县| 郯城县| 甘德县| 洛宁县| 彩票| 新郑市| 康马县| 灵丘县| 洪湖市| 英超| 阳朔县| 台中市| 永丰县| 灵武市| 大余县| 合江县| 宜良县| 阿荣旗| 海林市|