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

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

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

串行調(diào)用

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

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

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

但經(jīng)常地,幾個(gè)rpc相互之間沒有依賴關(guān)系的情況,這時(shí),我們稍加思考就會(huì)想到使用并發(fā)的方式,同時(shí)發(fā)出請(qǐng)求,阻塞等到所有請(qǐng)求返回,這樣,總體耗時(shí)就變成了Max(TimeA, TimeB, TimeC),我們可以通過常用的sync.WaitGroup輕松實(shí)現(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)實(shí)事件是不完美的,尤其是在加入了網(wǎng)絡(luò)這一因素后,我們經(jīng)常會(huì)需要處理調(diào)用失敗的情況,很多情況下,并發(fā)的幾個(gè)操作只要任一失敗,整個(gè)處理就算失敗了,但是由于WaitGroup要等所有調(diào)用都done才能返回,因此調(diào)用時(shí)間是由耗時(shí)最長(zhǎng)的那個(gè)(不一定是失敗的)決定的,如果不是失敗的那個(gè),其實(shí)就產(chǎn)生了資源浪費(fèi),如下圖,B最先失敗了,此時(shí)邏輯上已經(jīng)可以返回,但是實(shí)際卻等到了最長(zhǎng)的調(diào)用-A返回了整個(gè)函數(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實(shí)現(xiàn)并發(fā)調(diào)用

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

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

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

wg, groupCtx := errgroup.WithContext(ctx)

返回的第一個(gè)參數(shù)是*errgroup.Group,第二個(gè)則是在子調(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)用中第一個(gè)非nil的error,全成功的話就是nil。

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

因此整體,我們的代碼差不多就長(zhǎng)這個(gè)樣子

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 {
    // ... 錯(cuò)誤處理
    }
    // 全部成功
}

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

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

總結(jié)

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

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

相關(guān)文章

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

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

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

    Golang自動(dòng)追蹤GitHub上熱門AI項(xiàng)目

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

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

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

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

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

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

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

    Golang中的Interface詳解

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

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

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

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

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

    golang常用庫(kù)之pkg/errors包第三方錯(cuò)誤處理包案例詳解

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

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

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

最新評(píng)論

清流县| 革吉县| 绩溪县| 随州市| 始兴县| 万载县| 山东省| 桦南县| 聊城市| 安陆市| 太湖县| 张掖市| 新巴尔虎右旗| 洪湖市| 林周县| 崇信县| 唐海县| 遂宁市| 盱眙县| 项城市| 理塘县| 舞阳县| 吴旗县| 临澧县| 镇宁| 郎溪县| 子长县| 白山市| 安国市| 靖江市| 微博| 怀来县| 普格县| 新疆| 东安县| 城固县| 丹棱县| 康马县| 土默特右旗| 洛南县| 鹿邑县|