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

Go中g(shù)routine通信與context控制實(shí)例詳解

 更新時(shí)間:2022年02月11日 15:54:56   作者:DogTwo  
隨著context包的引入,標(biāo)準(zhǔn)庫中很多接口因此加上了context參數(shù),下面這篇文章主要給大家介紹了關(guān)于Go中g(shù)routine通信與context控制的相關(guān)資料,需要的朋友可以參考下

需求背景:

項(xiàng)目中需要定期執(zhí)行任務(wù)A來做一些輔助的工作,A的執(zhí)行需要在超時(shí)時(shí)間內(nèi)完成,如果本次執(zhí)行超時(shí)了,那就不對(duì)本次的執(zhí)行結(jié)果進(jìn)行處理(即放棄這次執(zhí)行)。同時(shí)A又依賴B,C兩個(gè)子任務(wù)的執(zhí)行結(jié)果。B, C之間相互獨(dú)立,可以并行的執(zhí)行。但無論B,C哪一個(gè)執(zhí)行失敗或超時(shí)都會(huì)導(dǎo)致本次任務(wù)執(zhí)行失敗。

Groutine的并發(fā)控制:

go中對(duì)于groutine的并發(fā)控制有三種解決方案:

  • 通過channel控制。

    父groutine中聲明無buffer的chan切片,向要開啟的子groutine中傳入切片中的一個(gè)chan

    子groutine執(zhí)行完成后向這個(gè)chan中寫入數(shù)據(jù)(可以是和父groutine通信的也可以不是)

    父groutine遍歷所有chan并執(zhí)行 <-chan 操作, 利用無buffer的channel只有讀寫同時(shí)準(zhǔn)備好才能執(zhí)行的特性進(jìn)行控

  • WaitGroup控制。

    通過sync.Waitgroup, 每開啟一個(gè)子groutine就執(zhí)行 wg.Add(1), 子groutine內(nèi)部執(zhí)行wg.Done(), 父groutine通過wg.Wait()等待所有子協(xié)程

  • Context控制。

    waitGroup和Context應(yīng)該是Go中較為常用的兩種并發(fā)控制。相較而言,context對(duì)于派生groutine有更強(qiáng)大的控制力,可以控制多級(jí)樹狀分布的groutine。

    當(dāng)然waitGroup的子groutine也可以再開啟新的waitGroup并且等待多個(gè)孫groutine, 但是不如context的控制更加方便.

Context:

context包提供了四個(gè)方法創(chuàng)建不同類型的context

  • WitchCancel()
  • WithDeadline()
  • WithTimeout()
  • WithValue()

WithValue()主要用于通過context傳遞一些上下文消息,不在本次討論中。WithTimeout和WithDeadLine幾乎是一致的。但無論哪種,控制groutine都需要使用ctx.Done()方法. Done() 方法返回一個(gè) "只讀"的chan <-chan struct{}, 需要編寫代碼監(jiān)聽這個(gè)chan,一旦收到它的消息就說明這個(gè)context應(yīng)當(dāng)結(jié)束了,無論是到達(dá)了超時(shí)時(shí)間還是在某個(gè)地方主動(dòng)cancel()了方法。

看看代碼:

var ch1 chan int
var ch2 chan int
<br>// 任務(wù)A, 通過最外層的for來控制定期執(zhí)行
func TestMe(t *testing.T) {
    ch1 = make(chan int, 0)
    ch2 = make(chan int, 0)
    count := 0
    for {
        count ++
        ctx, cancel := context.WithTimeout(context.Background(), time.Second * 2)<br>                // 任務(wù)A的邏輯部分,開啟子任務(wù)B, C。<br>                // B,C通過ch1,ch2和A通信。<br>                // 同時(shí)監(jiān)聽ctx.Done,如果超時(shí)了立即結(jié)束本次任務(wù)不繼續(xù)執(zhí)行
        go func(ctx context.Context) {
            go g1(ctx, count)
            go g2(ctx, count)
            v1, v2 := -1, -1
            for v1 == -1 || v2 == -1 {
                select {
                case <- ctx.Done():
                    cancel()
                    fmt.Println("父級(jí)2超時(shí)退出,當(dāng)前count值為", count, "當(dāng)前時(shí)間:", time.Now())
                    return
                case v1 = <- ch1:
                case v2 = <- ch2:
                }
            }
            fmt.Println("正常執(zhí)行完成退出, 開啟下次循環(huán),當(dāng)前count值為:", count, "當(dāng)前 v1: ", v1, "當(dāng)前 v2: ", v2)
        }(ctx)<br>                // 任務(wù)A監(jiān)控ctx是否到達(dá)timeOUT,timeout就終止本次執(zhí)行
        select {
        case <- ctx.Done():
            fmt.Println("父級(jí)1超時(shí)退出,當(dāng)前count值為", count, "當(dāng)前時(shí)間:", time.Now())
        }
        time.Sleep(time.Second * 3)
    }
}
<br>// 改進(jìn)后的任務(wù)B,即使計(jì)算出了結(jié)果,也不會(huì)再向ch1寫數(shù)據(jù)了,不會(huì)造成臟數(shù)據(jù)
func g1 (ctx context.Context, num int) {
    fmt.Println("g1 num", num, "time", time.Now())
    select {
    case <-ctx.Done():
        fmt.Println("子級(jí) g1關(guān)閉, 不向channel中寫數(shù)據(jù)")
        return
    default:
        ch1 <- num
    }
}
<br>// 改進(jìn)前的任務(wù)C
func g2 (ctx context.Context, num int) {
    fmt.Println("g2 num", num, "time", time.Now())
    ch2 <- num

基于上述代碼,子任務(wù)B, C的處理其實(shí)有一次較大的變動(dòng)。一開始B,C都是類似于子任務(wù)C,即g2的這種寫法。

這種寫法在執(zhí)行完成后就把自身的結(jié)果交給channel, 父groutine通過channel來讀取數(shù)據(jù),正常情況下也能工作。但異常情況下,如子任務(wù)B執(zhí)行完成,子任務(wù)C(即g2)因?yàn)榫W(wǎng)絡(luò)通信等原因執(zhí)行了5s(超過context的最大時(shí)長), 就會(huì)出現(xiàn)比較嚴(yán)重的問題。到達(dá)超時(shí)時(shí)間后,A檢測(cè)到了超時(shí)就自動(dòng)結(jié)束了本次任務(wù),但g2還在執(zhí)行過程中。g2執(zhí)行完成后向ch2寫數(shù)據(jù)阻塞了(因?yàn)锳已關(guān)閉,沒有讀取ch2的groutine)。下一個(gè)循環(huán)中A再次開啟讀取ch1與ch2, 實(shí)際上讀取ch1是當(dāng)次的結(jié)果,ch2是上次任務(wù)中g(shù)2返回的結(jié)果,導(dǎo)致兩處依賴的數(shù)據(jù)源不一致。

模擬上述情況,將g2做了一些改動(dòng)如下:

// 在第3次任務(wù)重等待3s, 使得它超時(shí)<br>func g2 (ctx context.Context, num int) {
    if num == 3 {
        time.Sleep(time.Second * 3)
    }
    fmt.Println("g2 num", num, "time", time.Now())
    ch2 <- num
}

實(shí)際上,如果想要通過context控制groutine, 一定要監(jiān)控Done()方法。如g1所示。相同情況下A超時(shí)退出,C仍在執(zhí)行。C執(zhí)行完成后先檢測(cè)Context是否已退出,如果已退出就不再向ch2中寫入本次的數(shù)據(jù)了。(拋磚引玉了,也可能有更好的寫法,希望大佬不吝賜教)

將g2改成和g1類似的寫法后測(cè)試結(jié)果如下:

func g2 (ctx context.Context, num int) {
    if num == 3 {
        time.Sleep(time.Second * 10)
        fmt.Println("這次g2 超時(shí),應(yīng)當(dāng)g1, g2都不返回")
    }
    fmt.Println("g2 num", num, "time", time.Now())
    select {
    case <-ctx.Done():
        fmt.Println("子級(jí) g2關(guān)閉, 不向channel中寫數(shù)據(jù)")
        return
    default:
        ch2 <- num
    }
}

總結(jié)

到此這篇關(guān)于Go中g(shù)routine通信與context控制的文章就介紹到這了,更多相關(guān)Go groutine通信與context控制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • golang gorm多條件篩選查詢操作

    golang gorm多條件篩選查詢操作

    這篇文章主要介紹了golang gorm多條件篩選查詢操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 淺析goland等待鎖問題

    淺析goland等待鎖問題

    這篇文章主要介紹了goland等待鎖問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2020-11-11
  • 如何使用?Go?和?Excelize?構(gòu)建電子表格

    如何使用?Go?和?Excelize?構(gòu)建電子表格

    這篇文章主要介紹了如何使用Go和Excelize構(gòu)建電子表格,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09
  • go語言里包的用法實(shí)例

    go語言里包的用法實(shí)例

    這篇文章主要介紹了go語言里包的用法,實(shí)例分析了Go語言里包的原理與使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • Go 數(shù)據(jù)庫查詢與結(jié)構(gòu)體映射的示例詳解

    Go 數(shù)據(jù)庫查詢與結(jié)構(gòu)體映射的示例詳解

    本文主要介紹了如何使用Go語言進(jìn)行數(shù)據(jù)庫查詢并將查詢結(jié)果映射到結(jié)構(gòu)體中,文章詳細(xì)講解了結(jié)構(gòu)體字段導(dǎo)出和db標(biāo)簽的使用方法,并通過示例代碼展示了如何正確地進(jìn)行數(shù)據(jù)庫查詢和結(jié)果映射
    2024-11-11
  • 一個(gè)簡(jiǎn)單的Golang實(shí)現(xiàn)的HTTP Proxy方法

    一個(gè)簡(jiǎn)單的Golang實(shí)現(xiàn)的HTTP Proxy方法

    今天小編就為大家分享一篇一個(gè)簡(jiǎn)單的Golang實(shí)現(xiàn)的HTTP Proxy方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • 在Go中格式化字符串的幾種常用方法

    在Go中格式化字符串的幾種常用方法

    Go對(duì)字符串格式化提供了良好的支持,這篇文章主要給大家介紹了關(guān)于在Go中格式化字符串的幾種常用方法,文中通過代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Go具有一定的參考價(jià)值,需要的朋友可以參考下
    2023-10-10
  • 解決Golang time.Parse和time.Format的時(shí)區(qū)問題

    解決Golang time.Parse和time.Format的時(shí)區(qū)問題

    這篇文章主要介紹了解決Golang time.Parse和time.Format的時(shí)區(qū)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 詳解Go中Set的實(shí)現(xiàn)方式

    詳解Go中Set的實(shí)現(xiàn)方式

    這篇文章主要介紹了詳解Go中Set的實(shí)現(xiàn)方式,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Go排序算法通用qsort函數(shù)使用示例

    Go排序算法通用qsort函數(shù)使用示例

    這篇文章主要為大家介紹了Go排序算法通用qsort函數(shù)使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11

最新評(píng)論

禹州市| 津南区| 东方市| 肥城市| 区。| 信阳市| 沙雅县| 阿坝县| 郯城县| 岳阳县| 长治县| 安龙县| 乐昌市| 星座| 昌乐县| 瑞昌市| 富宁县| 宜昌市| 额尔古纳市| 金阳县| 平泉县| 南城县| 上林县| 吉隆县| 上杭县| 瑞丽市| 夏河县| 汉中市| 秀山| 清苑县| 洱源县| 固始县| 上虞市| 招远市| 高青县| 黄龙县| 利津县| 克拉玛依市| 崇信县| 茶陵县| 桐乡市|