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

golang基于errgroup實現(xiàn)并發(fā)調(diào)用的方法

 更新時間:2022年09月05日 08:57:19   作者:夏日白云  
這篇文章主要介紹了golang基于errgroup實現(xiàn)并發(fā)調(diào)用,本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下

串行調(diào)用

在用go編寫web/rpc服務(wù)器的時候,經(jīng)常會出現(xiàn)需要對下游多 個/組 服務(wù)調(diào)用rpc(或者其他比較耗時的操作)的情況。
按照自然的寫法,比如對下游有ABC三個調(diào)用,串行順著寫,就總共要花費TimeA+TimeB+TimeC的時間:

func Handler(ctx context.Context) {
    var a, b, c respType
    a = A(ctx)
    b = B(ctx)
    c = C(ctx)
}

基于sync.WaitGroup實現(xiàn)簡單的并發(fā)調(diào)用

但經(jīng)常地,幾個rpc相互之間沒有依賴關(guān)系的情況,這時,我們稍加思考就會想到使用并發(fā)的方式,同時發(fā)出請求,阻塞等到所有請求返回,這樣,總體耗時就變成了Max(TimeA, TimeB, TimeC),我們可以通過常用的sync.WaitGroup輕松實現(xiàn)這事:

func Handler(ctx context.Context) {
    var a, b, c respType
   	wg := sync.WaitGroup{}
	wg.Add(3)
	go func() {
		defer wg.Done()
		a = A(ctx)
	}()
	go func() {
		defer wg.Done()
		b = B(ctx)
	}()
	go func() {
		defer wg.Done()
		c = C(ctx)
	}()
	wg.Wait()
}

但是現(xiàn)實事件是不完美的,尤其是在加入了網(wǎng)絡(luò)這一因素后,我們經(jīng)常會需要處理調(diào)用失敗的情況,很多情況下,并發(fā)的幾個操作只要任一失敗,整個處理就算失敗了,但是由于WaitGroup要等所有調(diào)用都done才能返回,因此調(diào)用時間是由耗時最長的那個(不一定是失敗的)決定的,如果不是失敗的那個,其實就產(chǎn)生了資源浪費,如下圖,B最先失敗了,此時邏輯上已經(jīng)可以返回,但是實際卻等到了最長的調(diào)用-A返回了整個函數(shù)才返回:

func Handler(ctx context.Context) {
    var a, b, c respType
    var errA, errB, errC error
   	wg := sync.WaitGroup{}
	wg.Add(3)
	go func() {
		defer wg.Done()
		a, errA = A(ctx)
	}()
	go func() {
		defer wg.Done()
		b, errB = B(ctx)
	}()
	go func() {
		defer wg.Done()
		c, errC = C(ctx)
	}()
	wg.Wait()
	if errA != nil {
	// ...
	}
	if errB != nil {
	// ...
	}
	if errC != nil {
	// ...
	}
}

基于errgroup.Group實現(xiàn)并發(fā)調(diào)用

這對于追求極致的我們來說顯然是不能接受的,我們希望達到,如果有任意一個調(diào)用報錯,立刻讓所有調(diào)用返回的效果:

好在,我們有現(xiàn)成的工具可以用,通過引入"golang.org/x/sync/errgroup",可以輕松實現(xiàn)上面的目的。

為了使用errgroup,先使用WithContext方法創(chuàng)建一個Group

wg, groupCtx := errgroup.WithContext(ctx)

返回的第一個參數(shù)是*errgroup.Group,第二個則是在子調(diào)用中應(yīng)該使用的context。

然后,使用Go方法調(diào)用所有的并發(fā)方法

	wg.Go(func() error {
		var err error
		a, err = A(groupCtx)
		return err
	})

最后, 使用Wait方法等待并發(fā)結(jié)束,返回值是所有子調(diào)用中第一個非nil的error,全成功的話就是nil。

if err := wg.Wait(); err != nil {
// ...
}

因此整體,我們的代碼差不多就長這個樣子

func handler(ctx context.Context) {
    var a, b, c respType
    wg, groupCtx := errgroup.WithContext(ctx)
	wg.Go(func() error {
		var err error
		a, err = A(groupCtx)
		return err
	})
	wg.Go(func() error {
		var err error
		b, err = B(groupCtx)
		return err
	})
	wg.Go(func() error {
		var err error
		c, err = C(groupCtx)
		return err
	})
	if err := wg.Wait(); err != nil {
    // ... 錯誤處理
    }
    // 全部成功
}

errgroup內(nèi)部通過封裝了waitGroup和sync.Once實現(xiàn)了這個語法糖。

使用時特別要注意的是,errgroup的提前取消調(diào)用rpc是通過cancel那個返回的context(即上面的groupCtx)實現(xiàn)的,因此在所有子調(diào)用中都要實現(xiàn)監(jiān)聽groupCtx的Done事件。而在正常的rpc框架中都已經(jīng)幫我們實現(xiàn)了這件事,因此我們只要保證傳進去的是groupCtx即可。

總結(jié)

errgroup幫我們封裝了并發(fā)調(diào)用下游時快速失敗的邏輯,我們能很方便地使用它進行業(yè)務(wù)代碼的編寫。使用的關(guān)鍵是一定要記得在子調(diào)用中傳遞WithContext中返回的Context。

好用的工具千千萬,讓我們一個個來掌握!

相關(guān)文章

  • etcd通信接口之客戶端API核心方法實戰(zhàn)

    etcd通信接口之客戶端API核心方法實戰(zhàn)

    這篇文章主要為大家介紹了etcd通信接口之客戶端API核心方法實戰(zhàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • Golang自動追蹤GitHub上熱門AI項目

    Golang自動追蹤GitHub上熱門AI項目

    這篇文章主要為大家介紹了Golang自動追蹤GitHub上熱門AI項目,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • Golang在Window環(huán)境使用Imagick7的過程

    Golang在Window環(huán)境使用Imagick7的過程

    這篇文章主要介紹了Golang在Window環(huán)境使用Imagick7的過程,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2023-11-11
  • Golang實現(xiàn)單元測試中的邏輯層

    Golang實現(xiàn)單元測試中的邏輯層

    前面我們完成了最麻煩的數(shù)據(jù)層的單元測試,今天我們來看看單元測試中最容易做的一層,數(shù)據(jù)邏輯層,也就是我們通常說的 service 或者 biz 等
    2023-03-03
  • 一文帶你了解Go語言中的指針和結(jié)構(gòu)體

    一文帶你了解Go語言中的指針和結(jié)構(gòu)體

    前面的兩篇文章對?Go?語言的基礎(chǔ)語法和基本數(shù)據(jù)類型以及幾個復(fù)合數(shù)據(jù)類型進行介紹,本文將對?Go?里面的指針和結(jié)構(gòu)體進行介紹,也為后續(xù)文章做鋪墊,感興趣的可以了解一下
    2022-11-11
  • Golang中的Interface詳解

    Golang中的Interface詳解

    本文詳細講解了Golang中的Interface,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-07-07
  • 使用Golang如何實現(xiàn)簡易的令牌桶算法

    使用Golang如何實現(xiàn)簡易的令牌桶算法

    這篇文章主要介紹了使用Golang如何實現(xiàn)簡易的令牌桶算法問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 使用Singleflight實現(xiàn)Golang代碼優(yōu)化

    使用Singleflight實現(xiàn)Golang代碼優(yōu)化

    有許多方法可以優(yōu)化代碼以提高效率,減少運行進程就是其中之一,本文我們就來學(xué)習(xí)一下如何通過使用一個Go包Singleflight來減少重復(fù)進程,從而優(yōu)化Go代碼吧
    2023-09-09
  • golang常用庫之pkg/errors包第三方錯誤處理包案例詳解

    golang常用庫之pkg/errors包第三方錯誤處理包案例詳解

    這篇文章主要介紹了golang常用庫之pkg/errors包第三方錯誤處理包,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • Go語言LeetCode題解706設(shè)計哈希映射

    Go語言LeetCode題解706設(shè)計哈希映射

    這篇文章主要為大家介紹了Go語言LeetCode題解706設(shè)計哈希映射示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12

最新評論

莱西市| 依兰县| 家居| 福清市| 汾阳市| 五莲县| 横峰县| 贡山| 临澧县| 永顺县| 仲巴县| 华容县| 腾冲县| 湟中县| 隆安县| 盈江县| 伊宁县| 衡山县| 三河市| 石屏县| 浦县| 宁津县| 潼南县| 香河县| 武陟县| 五指山市| 禄劝| 正定县| 东宁县| 台南县| 大庆市| 应城市| 长宁区| 多伦县| 安岳县| 孟连| 玛纳斯县| 桐城市| 定陶县| 荥经县| 太仓市|