婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av

主頁 > 知識庫 > Go并發控制WaitGroup的使用場景分析

Go并發控制WaitGroup的使用場景分析

熱門標簽:揚州電銷外呼系統軟件 電腦外呼系統輻射大嗎 上海企業外呼系統排名 開通400電話申請流程 智能語音電銷的機器人 如何利用高德地圖標注家 武漢百應人工智能電銷機器人 百度地圖標注位置網站 400手機電話免費辦理

1. 前言

上一篇介紹了 Go并發控制--Channel

使用channel來控制子協程的優點是實現簡單,缺點是當需要大量創建協程時就需要有相同數量的channel,而且對于子協程繼續派生出來的協程不方便控制。

2. 使用WaitGroup控制

WaitGroup,可理解為Wait-Goroutine-Group,即等待一組goroutine結束。比如某個goroutine需要等待其他幾個goroutine全部完成,那么使用WaitGroup可以輕松實現。


2.1 使用場景

下面程序展示了一個goroutine等待另外兩個goroutine結束的例子:

package main

import (
    "fmt"
    "time"
    "sync"
)

func main() {
    var wg sync.WaitGroup

    wg.Add(2) //設置計數器,數值即為goroutine的個數
    go func() {
        //Do some work
        time.Sleep(1*time.Second)

        fmt.Println("Goroutine 1 finished!")
        wg.Done() //goroutine執行結束后將計數器減1
    }()

    go func() {
        //Do some work
        time.Sleep(2*time.Second)

        fmt.Println("Goroutine 2 finished!")
        wg.Done() //goroutine執行結束后將計數器減1
    }()

    wg.Wait() //主goroutine阻塞等待計數器變為0
    fmt.Printf("All Goroutine finished!")
}

簡單的說,上面程序中wg內部維護了一個計數器:

  • 啟動goroutine前將計數器通過Add(2)將計數器設置為待啟動的goroutine個數。
  • 啟動goroutine后,使用Wait()方法阻塞自己,等待計數器變為0。
  • 每個goroutine執行結束通過Done()方法將計數器減1。
  • 計數器變為0后,阻塞的goroutine被喚醒

其實WaitGroup也可以實現一組goroutine等待另一組goroutine,這有點像玩雜技,很容出錯,如果不了解其實現原理更是如此。實際上,WaitGroup的實現源碼非常簡單。


2.2 信號量

信號量是Unix系統提供的一種保護共享資源的機制,用于防止多個線程同時訪問某個資源

可簡單理解為信號量為一個數值:

  • 當信號量>0時,表示資源可用,獲取信號量時系統自動將信號量減1;
  • 當信號量==0時,表示資源暫不可用,獲取信號量時,當前線程會進入睡眠,當信號量為正時被喚醒;

1.3 WaitGroup 數據結構

源碼包中src/sync/waitgroup.go:WaitGroup定義了其數據結構:

type WaitGroup struct {
    state1 [3]uint32
}

state1是個長度為3的數組,其中包含了state和一個信號量,而state實際上是兩個計數器:

  • counter: 當前還未執行結束的goroutine計數器
  • waiter count: 等待goroutine-group結束的goroutine數量,即有多少個等候者
  • semaphore: 信號量

考慮到字節是否對齊,三者出現的位置不同,為簡單起見,依照字節已對齊情況下,三者在內存中的位置如下所示:

WaitGroup對外提供三個接口:

  • Add(delta int): 將delta值加到counter中
  • Wait(): waiter遞增1,并阻塞等待信號量semaphore
  • Done(): counter遞減1,按照waiter數值釋放相應次數信號量

下面分別介紹這三個函數的實現細節。

2.3.1 Add () 方法

Add()做了兩件事,一是把delta值累加到counter中,因為delta可以為負值,也就是說counter有可能變成0或負值,所以第二件事就是當counter值變為0時,根據waiter數值釋放等量的信號量,把等待的goroutine全部喚醒,如果counter變為負值,則panic.

Add()偽代碼如下:

func (wg *WaitGroup) Add(delta int) {
    statep, semap := wg.state() //獲取state和semaphore地址指針

    state := atomic.AddUint64(statep, uint64(delta)32) //把delta左移32位累加到state,即累加到counter中
    v := int32(state >> 32) //獲取counter值
    w := uint32(state)      //獲取waiter值

    if v  0 {              //經過累加后counter值變為負值,panic
        panic("sync: negative WaitGroup counter")
    }

    //經過累加后,此時,counter >= 0
    //如果counter為正,說明不需要釋放信號量,直接退出
    //如果waiter為零,說明沒有等待者,也不需要釋放信號量,直接退出
    if v > 0 || w == 0 {
        return
    }

    //此時,counter一定等于0,而waiter一定大于0(內部維護waiter,不會出現小于0的情況),
    //先把counter置為0,再釋放waiter個數的信號量
    *statep = 0
    for ; w != 0; w-- {
        runtime_Semrelease(semap, false) //釋放信號量,執行一次釋放一個,喚醒一個等待者
    }
}

2.3.2 Wait()

Wait()方法也做了兩件事,一是累加waiter, 二是阻塞等待信號量

func (wg *WaitGroup) Wait() {
    statep, semap := wg.state() //獲取state和semaphore地址指針
    for {
        state := atomic.LoadUint64(statep) //獲取state值
        v := int32(state >> 32)            //獲取counter值
        w := uint32(state)                 //獲取waiter值
        if v == 0 {                        //如果counter值為0,說明所有goroutine都退出了,不需要待待,直接返回
            return
        }

        // 使用CAS(比較交換算法)累加waiter,累加可能會失敗,失敗后通過for loop下次重試
        if atomic.CompareAndSwapUint64(statep, state, state+1) {
            runtime_Semacquire(semap) //累加成功后,等待信號量喚醒自己
            return
        }
    }
}

這里用到了CAS算法保證有多個goroutine同時執行Wait()時也能正確累加waiter。

2.3.3 Done()

Done()只做一件事,即把counter減1,我們知道Add()可以接受負值,所以Done實際上只是調用了Add(-1)。

源碼如下:

func (wg *WaitGroup) Done() {
    wg.Add(-1)
}

Done()的執行邏輯就轉到了Add(),實際上也正是最后一個完成的goroutine把等待者喚醒的。

2.4 總結

簡單說來,WaitGroup通常用于等待一組“工作協程”結束的場景,其內部維護兩個計數器,這里把它們稱為“工作協程”計數器和“坐等協程”計數器,
WaitGroup對外提供的三個方法分工非常明確:

  • Add(delta int)方法用于增加“工作協程”計數,通常在啟動新的“工作協程”之前調用;
  • Done()方法用于減少“工作協程”計數,每次調用遞減1,通常在“工作協程”內部且在臨近返回之前調用;
  • Wait()方法用于增加“坐等協程”計數,通常在所有”工作協

Done()方法除了負責遞減“工作協程”計數以外,還會在“工作協程”計數變為0時檢查“坐等協程”計數器并把“坐等協程”喚醒。

需要注意

  • Done()方法遞減“工作協程”計數后,如果“工作協程”計數變成負數時,將會觸發panic,這就要求Add()方法調用要早于Done()方法。
  • 也就是說代碼中,如果調用Done的次數多于Add的次數會產生painc
  • 當“工作協程”計數多于實際需要等待的“工作協程”數量時,“坐等協程”可能會永遠無法被喚醒而產生列鎖,此時,Go運行時檢測到死鎖會觸發panic
  • Add的添加的工作協程的數量,多于Done調用的次數,則會出現panic
  • 當“工作協程”計數小于實際需要等待的“工作協程”數量時,Done()會在“工作協程”計數變為負數時觸發panic。
  • Add()添加的工作協程個數小于Done調用的次數,會出現panic


3. 總結

WaitGroup控制子協程的方式很簡單,且目的很明確,等待一組子協程執行完畢再執行主線程,但是當子協程里面有子協程,子協程里面有其他的子協程時,這種并不知道有多少個子協程的情況下使用WaitGroup就很難,所以就需要****Context**上場了

到此這篇關于Go并發控制--WaitGroup篇的文章就介紹到這了,更多相關Go并發控制WaitGroup內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • Golang 實現分片讀取http超大文件流和并發控制
  • Go 并發控制context實現原理剖析(小結)
  • Django Channels 實現點對點實時聊天和消息推送功能
  • 基于django channel實現websocket的聊天室的方法示例
  • Go并發控制Channel使用場景分析

標簽:張掖 嘉峪關 江西 宜賓 黑龍江 延邊 武漢 新余

巨人網絡通訊聲明:本文標題《Go并發控制WaitGroup的使用場景分析》,本文關鍵詞  并發,控制,WaitGroup,的,使用,;如發現本文內容存在版權問題,煩請提供相關信息告之我們,我們將及時溝通與處理。本站內容系統采集于網絡,涉及言論、版權與本站無關。
  • 相關文章
  • 下面列出與本文章《Go并發控制WaitGroup的使用場景分析》相關的同類信息!
  • 本頁收集關于Go并發控制WaitGroup的使用場景分析的相關信息資訊供網民參考!
  • 推薦文章
    婷婷综合国产,91蜜桃婷婷狠狠久久综合9色 ,九九九九九精品,国产综合av
    久久久久久久网| 日本欧美一区二区| 久久奇米777| 亚洲3atv精品一区二区三区| 一区二区在线观看不卡| 国产精品夜夜爽| 久久精品夜色噜噜亚洲a∨ | 国产精品理论在线观看| 国产精品资源网| 91福利社在线观看| 亚洲青青青在线视频| 国产精品1024| 亚洲乱码国产乱码精品精的特点 | 久久久美女毛片| 成人av在线电影| 亚洲va欧美va天堂v国产综合| 欧美日韩免费视频| 国产一区二区影院| 国产精品卡一卡二| 欧美喷水一区二区| 国产成人午夜精品5599| 日日夜夜免费精品| 亚洲桃色在线一区| 久久综合成人精品亚洲另类欧美| 成人激情图片网| 久久se精品一区二区| 亚洲永久免费av| 国产精品女同一区二区三区| 欧美日韩一级片网站| 国产剧情在线观看一区二区| 日本中文一区二区三区| 亚洲国产精品视频| 亚洲精品一区二区三区在线观看| 成人免费观看视频| 青草av.久久免费一区| 亚洲精品欧美综合四区| 国产视频在线观看一区二区三区| 欧美顶级少妇做爰| 欧美一区二区三区小说| 欧美日韩综合在线| 欧美日韩成人一区| 日本一区二区免费在线观看视频| 国产日产欧美一区二区三区| 欧美一级夜夜爽| xnxx国产精品| 亚洲美女免费视频| 在线综合视频播放| 成人免费视频一区| 美腿丝袜亚洲综合| 亚洲6080在线| 狂野欧美性猛交blacked| 日韩精品色哟哟| 国产乱一区二区| 99久久国产免费看| 欧美日韩精品免费| 国产亚洲视频系列| 中文字幕第一区综合| 亚洲精品写真福利| 国产婷婷精品av在线| 国产精品久久久久永久免费观看 | 国产精品白丝jk黑袜喷水| 国产mv日韩mv欧美| 538prom精品视频线放| 中文字幕五月欧美| 美女免费视频一区二区| 色婷婷综合激情| 国产精品女主播av| 午夜精品在线看| 成人高清视频在线观看| 久久色在线观看| 激情文学综合插| 欧美日韩一区高清| 亚洲国产精品欧美一二99| 免费高清在线一区| 欧美精品少妇一区二区三区| 亚洲视频一区二区免费在线观看| 亚洲精品大片www| 在线影视一区二区三区| 久久久久成人黄色影片| 麻豆成人av在线| 日韩欧美精品在线视频| 久久精品72免费观看| 欧美美女直播网站| 久久99国产精品久久| 欧美精品自拍偷拍动漫精品| 一区二区三区日韩精品| 91成人看片片| 天天影视色香欲综合网老头| 精品久久人人做人人爽| 一本一道综合狠狠老| 亚洲国产一区二区三区青草影视| 国产成人精品一区二| 综合久久综合久久| 91精品国产综合久久久蜜臀图片| 日韩av网站在线观看| 欧美激情综合在线| 欧美日韩国产一二三| 国产一区二区网址| 亚洲欧美福利一区二区| 欧美—级在线免费片| 日韩欧美一二三四区| 不卡欧美aaaaa| 紧缚捆绑精品一区二区| 久久青草国产手机看片福利盒子| 久久国产成人午夜av影院| 一区av在线播放| 欧美韩国日本综合| 粉嫩嫩av羞羞动漫久久久| k8久久久一区二区三区| 亚洲国产精品久久一线不卡| 欧美在线你懂的| 2021久久国产精品不只是精品| 欧美三片在线视频观看| 偷拍一区二区三区| 欧美日韩成人高清| 《视频一区视频二区| 不卡一区中文字幕| 国产日韩av一区二区| 欧美图区在线视频| 成人不卡免费av| 国产成人一区二区精品非洲| 国产一区在线看| 精品中文字幕一区二区小辣椒| 日本一区二区高清| 欧美高清性hdvideosex| 欧美怡红院视频| 亚洲成av人影院| 亚洲不卡一区二区三区| 亚洲一区二区av在线| 天堂影院一区二区| 欧美一级日韩不卡播放免费| 国产精品2024| 亚洲欧美一区二区三区久本道91| 狠狠v欧美v日韩v亚洲ⅴ| 欧美精品视频www在线观看| 日韩视频在线你懂得| 91麻豆.com| 91黄色免费版| 2欧美一区二区三区在线观看视频 337p粉嫩大胆噜噜噜噜噜91av | 久久久久高清精品| 久久天堂av综合合色蜜桃网| 1024成人网色www| 久久精品夜色噜噜亚洲aⅴ| 一区二区三区四区在线播放 | 91福利在线播放| 精品一区二区三区在线播放 | 亚洲色图制服诱惑| 亚洲午夜免费视频| 色综合久久综合网| 亚洲免费大片在线观看| 一本一本大道香蕉久在线精品 | 亚洲伊人色欲综合网| 奇米一区二区三区| 在线欧美一区二区| 一区二区在线免费| 欧美日韩精品欧美日韩精品一 | 亚洲欧美日韩国产手机在线| 国产东北露脸精品视频| 国产欧美日韩综合| 丰满岳乱妇一区二区三区 | 亚洲电影在线免费观看| 91视频xxxx| 日韩av一区二区在线影视| 在线播放日韩导航| 蜜臀精品一区二区三区在线观看 | 亚洲福利一区二区三区| 欧美日韩美女一区二区| 美女www一区二区| 亚洲精品日韩专区silk| 亚洲婷婷综合色高清在线| 久久精品日韩一区二区三区| 成人激情av网| 韩国毛片一区二区三区| 亚洲精品免费电影| 国产欧美日本一区二区三区| 91黄色免费看| 白白色亚洲国产精品| 老司机午夜精品| 丝袜诱惑制服诱惑色一区在线观看| 欧美一区二区日韩一区二区| 国产精品系列在线观看| 婷婷久久综合九色综合伊人色| 久久久蜜桃精品| 欧美肥胖老妇做爰| 91网上在线视频| 波多野结衣欧美| 国产在线精品一区二区三区不卡| 亚洲免费在线视频一区 二区| 91成人在线免费观看| 在线观看区一区二| 一本久道久久综合中文字幕| 波多野结衣在线一区| 99精品热视频| 91免费国产在线| 欧美一区二区三区在线视频| 欧美一级片在线观看| 欧美一区二区成人6969| 久久女同精品一区二区| 中文字幕中文在线不卡住| 亚洲一二三四在线|