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

Go進(jìn)階并發(fā)控制channel和WaitGroup的實(shí)現(xiàn)

 更新時(shí)間:2026年06月05日 10:09:07   作者:念何架構(gòu)之路  
本篇文章詳細(xì)介紹了Go語(yǔ)言中的channel、WaitGroup和信號(hào)量三種并發(fā)控制機(jī)制,分別從實(shí)現(xiàn)原理、使用示例和優(yōu)缺點(diǎn)等方面進(jìn)行了深入解析,幫助開發(fā)者更好地掌握Go語(yǔ)言的并發(fā)編程技巧

1.Channel

channel一般用于協(xié)程之間的通信.不過(guò)channel也可以用于并發(fā)控制.比如主協(xié)程啟動(dòng)N個(gè)子協(xié)程.主協(xié)程等待所有子協(xié)程退出后再繼續(xù)后續(xù)流程.這種場(chǎng)景下channel也可輕易實(shí)現(xiàn)并發(fā)控制.

場(chǎng)景示例:

package main

import (
    "fmt"
    "gomodule/data"
    _ "gomodule/pubsub"
    "time"
)

func main() {
    //創(chuàng)建一個(gè)有10個(gè)元素的channel
    channel := make([]chan int, 10)
    for i := 0; i < 10; i++ {
       //切片中放入一個(gè)channel
       channel[i] = make(chan int)
       //啟動(dòng)協(xié)程
       go Process(channel[i])
    }

    for i, ch := range channel {
       <-ch
       fmt.Println("Routine ", i, "quit!")
    }
}

func Process(ch chan int) {
    time.Sleep(1 * time.Second)
    //管道寫入一個(gè)元素代表協(xié)程結(jié)束.
    ch <- 1
}

上面程序通過(guò)創(chuàng)建N個(gè)channel管理N個(gè)協(xié)程.每個(gè)協(xié)程都有一個(gè)channel用于與父協(xié)程通信.父協(xié)程創(chuàng)建完所有協(xié)程等待所有協(xié)程結(jié)束.

優(yōu)點(diǎn):

實(shí)現(xiàn)簡(jiǎn)單.

缺點(diǎn):

需要大量創(chuàng)建協(xié)程就需要相同數(shù)量的channel.對(duì)于子協(xié)程繼續(xù)派生出來(lái)的協(xié)程不方便控制.

2.WaitGroup:

WaitGroup可理解為Wait-Goroutine-Group.等待一組goroutine結(jié)束.示例如下.

package main

import (
    "fmt"
    "gomodule/data"
    _ "gomodule/pubsub"
    "sync"
    "time"
)

func main() {
    var wg sync.WaitGroup
    //計(jì)數(shù)器.數(shù)值是goroutine的個(gè)數(shù).
    wg.Add(2)
    go func() {
       time.Sleep(1 * time.Second)
       fmt.Println("goroutine 1 finish")
       //計(jì)數(shù)器減一.
       wg.Done()
    }()

    go func() {
       time.Sleep(2 * time.Second)
       fmt.Println("goroutine 2 finish")
       wg.Done()
    }()

    //主goroutine阻塞等待計(jì)數(shù)器變?yōu)?.
    wg.Wait()
    fmt.Println("all goroutine finish")
}

執(zhí)行結(jié)果如下:

1).啟動(dòng)goroutine前通過(guò)Add(2)方法將計(jì)數(shù)器設(shè)置為待啟動(dòng)goroutine個(gè)數(shù).

2).啟動(dòng)goroutine通過(guò)wait方法阻塞自己.等待計(jì)數(shù)器變?yōu)?.

3).每個(gè)goroutine執(zhí)行結(jié)束后通過(guò)Done方法將計(jì)數(shù)器減1.

4).計(jì)數(shù)器變?yōu)?后.阻塞的goroutine被喚醒.

2.1信號(hào)量:

信號(hào)量是UNIX系統(tǒng)提供的一種保護(hù)共享資源的機(jī)制.用于防止多個(gè)線程同時(shí)訪問某個(gè)資源.當(dāng)信號(hào)量>0時(shí).表示資源可用.獲取信號(hào)量時(shí)系統(tǒng)自動(dòng)將信號(hào)量減一.當(dāng)信號(hào)量=0時(shí).表示資源暫時(shí)不可用.獲取信號(hào)量時(shí).當(dāng)前線程會(huì)進(jìn)入睡眠.當(dāng)信號(hào)量為正時(shí)被喚醒.

2.2WaitGroup數(shù)據(jù)結(jié)構(gòu):

源碼位于src/sync/waitgroup.go:WaitGroup中.結(jié)構(gòu)如下.

type WaitGroup struct {
    noCopy noCopy

    state atomic.Uint64 // high 32 bits are counter, low 32 bits are waiter count.
    sema  uint32
}

state代表信號(hào)量.高32位代表信號(hào)量數(shù)量.低32位代表等待數(shù)量.

2.3WaitGroup對(duì)外方法:

Add(delta int):

func (wg *WaitGroup) Add(delta int) {
    if race.Enabled {
       if delta < 0 {
          // Synchronize decrements with Wait.
          race.ReleaseMerge(unsafe.Pointer(wg))
       }
       race.Disable()
       defer race.Enable()
    }
    state := wg.state.Add(uint64(delta) << 32)
    v := int32(state >> 32)
    w := uint32(state)
    if race.Enabled && delta > 0 && v == int32(delta) {
       // The first increment must be synchronized with Wait.
       // Need to model this as a read, because there can be
       // several concurrent wg.counter transitions from 0.
       race.Read(unsafe.Pointer(&wg.sema))
    }
    if v < 0 {
       panic("sync: negative WaitGroup counter")
    }
    if w != 0 && delta > 0 && v == int32(delta) {
       panic("sync: WaitGroup misuse: Add called concurrently with Wait")
    }
    if v > 0 || w == 0 {
       return
    }
    // This goroutine has set counter to 0 when waiters > 0.
    // Now there can't be concurrent mutations of state:
    // - Adds must not happen concurrently with Wait,
    // - Wait does not increment waiters if it sees counter == 0.
    // Still do a cheap sanity check to detect WaitGroup misuse.
    if wg.state.Load() != state {
       panic("sync: WaitGroup misuse: Add called concurrently with Wait")
    }
    // Reset waiters count to 0.
    wg.state.Store(0)
    for ; w != 0; w-- {
       runtime_Semrelease(&wg.sema, false, 0)
    }
}

Wait():

func (wg *WaitGroup) Wait() {
    if race.Enabled {
       race.Disable()
    }
    for {
       state := wg.state.Load()
       v := int32(state >> 32)
       w := uint32(state)
       if v == 0 {
          // Counter is 0, no need to wait.
          if race.Enabled {
             race.Enable()
             race.Acquire(unsafe.Pointer(wg))
          }
          return
       }
       // Increment waiters count.
       if wg.state.CompareAndSwap(state, state+1) {
          if race.Enabled && w == 0 {
             // Wait must be synchronized with the first Add.
             // Need to model this is as a write to race with the read in Add.
             // As a consequence, can do the write only for the first waiter,
             // otherwise concurrent Waits will race with each other.
             race.Write(unsafe.Pointer(&wg.sema))
          }
          runtime_SemacquireWaitGroup(&wg.sema)
          if wg.state.Load() != 0 {
             panic("sync: WaitGroup is reused before previous Wait has returned")
          }
          if race.Enabled {
             race.Enable()
             race.Acquire(unsafe.Pointer(wg))
          }
          return
       }
    }
}

Done():

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

done方法就是調(diào)用add方法進(jìn)行加-1.

小結(jié):

1).Add方法用于增加工作協(xié)程計(jì)數(shù).通常在啟動(dòng)新的工作協(xié)程之前調(diào)用.

2).Done方法用于減少工作協(xié)程計(jì)數(shù).每次調(diào)用遞減1.通常在工作協(xié)程內(nèi)部且臨近返回之前調(diào)用.

3).Wait方法用于增加坐等協(xié)程計(jì)數(shù).通常在所有協(xié)程全部啟動(dòng)之后調(diào)用.

注:

Add方法累加的工作協(xié)程計(jì)數(shù)要和實(shí)際需要等待的工作協(xié)程數(shù)要一致.否則也會(huì)出發(fā)panic.

當(dāng)工作協(xié)程計(jì)數(shù)多于實(shí)際需要等待的工作協(xié)程數(shù)量時(shí).可能會(huì)因?yàn)闊o(wú)法喚醒死鎖.Go運(yùn)行檢測(cè)到死鎖就會(huì)發(fā)生panic.當(dāng)工作協(xié)程計(jì)數(shù)小于實(shí)際等待的工作協(xié)程數(shù)量時(shí).Done方法會(huì)在工作協(xié)程計(jì)數(shù)變?yōu)樨?fù)時(shí)出發(fā)panic.

到此這篇關(guān)于Go進(jìn)階并發(fā)控制channel和WaitGroup的文章就介紹到這了,更多相關(guān)Go并發(fā)控制channel和WaitGroup內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go并發(fā)編程結(jié)構(gòu)體多字段原子操作示例詳解

    Go并發(fā)編程結(jié)構(gòu)體多字段原子操作示例詳解

    這篇文章主要為大家介紹了Go并發(fā)編程結(jié)構(gòu)體多字段原子操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 淺析Go語(yǔ)言中數(shù)組的這些細(xì)節(jié)

    淺析Go語(yǔ)言中數(shù)組的這些細(xì)節(jié)

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言中數(shù)組一些細(xì)節(jié)的相關(guān)資料,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Go語(yǔ)言有一定的幫助,需要的可以了解一下
    2022-11-11
  • go語(yǔ)言實(shí)戰(zhàn)之實(shí)現(xiàn)比特幣地址校驗(yàn)步驟

    go語(yǔ)言實(shí)戰(zhàn)之實(shí)現(xiàn)比特幣地址校驗(yàn)步驟

    這篇文章主要介紹了go語(yǔ)言實(shí)戰(zhàn)之實(shí)現(xiàn)比特幣地址校驗(yàn)步驟,利用生產(chǎn)的隨機(jī)數(shù)采用橢圓加密算法生成公鑰,具體步驟實(shí)例代碼請(qǐng)參考下本文
    2021-05-05
  • Go語(yǔ)言的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)JSON

    Go語(yǔ)言的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)JSON

    本文主要介紹了Go語(yǔ)言的數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)JSON,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 詳解golang中模板的常用語(yǔ)法

    詳解golang中模板的常用語(yǔ)法

    這篇文章主要介紹了golang模板中的常用語(yǔ)法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-08-08
  • 圖文詳解Go程序如何編譯并運(yùn)行起來(lái)的

    圖文詳解Go程序如何編譯并運(yùn)行起來(lái)的

    Go語(yǔ)言這兩年在語(yǔ)言排行榜上的上升勢(shì)頭非常猛,Go語(yǔ)言雖然是靜態(tài)編譯型語(yǔ)言,但是它卻擁有腳本化的語(yǔ)法,下面這篇文章主要給大家介紹了關(guān)于Go程序如何編譯并運(yùn)行起來(lái)的相關(guān)資料,需要的朋友可以參考下
    2024-05-05
  • Linux操作系統(tǒng)上打包Go項(xiàng)目實(shí)現(xiàn)方式

    Linux操作系統(tǒng)上打包Go項(xiàng)目實(shí)現(xiàn)方式

    文章介紹了Go項(xiàng)目依賴打包的兩種方法:GoModules(管理依賴并確保一致性)和靜態(tài)鏈接(嵌入依賴生成獨(dú)立可執(zhí)行文件),需注意cgo配置及系統(tǒng)兼容性,推薦根據(jù)需求選擇合適方式
    2025-08-08
  • Go中各種newreader和newbuffer的使用總結(jié)

    Go中各種newreader和newbuffer的使用總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Go語(yǔ)言中各種newreader和newbuffer的使用的相關(guān)資料,文中的示例代碼講解詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴可以了解下
    2023-11-11
  • go等待一組協(xié)程結(jié)束的操作方式

    go等待一組協(xié)程結(jié)束的操作方式

    這篇文章主要介紹了go等待一組協(xié)程結(jié)束的操作方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-05-05
  • golang簡(jiǎn)易令牌桶算法實(shí)現(xiàn)代碼

    golang簡(jiǎn)易令牌桶算法實(shí)現(xiàn)代碼

    這篇文章主要介紹了golang簡(jiǎn)易令牌桶算法實(shí)現(xiàn)代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04

最新評(píng)論

东乡族自治县| 怀宁县| 屏南县| 太仆寺旗| 镇原县| 宁陵县| 邯郸县| 田东县| 全南县| 尉氏县| 双鸭山市| 孝义市| 察雅县| 城口县| 广饶县| 土默特右旗| 临漳县| 旅游| 揭东县| 江达县| 龙陵县| 四子王旗| 宁津县| 温宿县| 桓仁| 泰州市| 湘潭市| 互助| 大城县| 永城市| 海宁市| 社旗县| 介休市| 大庆市| 喀什市| 兴安县| 班玛县| 老河口市| 镇安县| 万载县| 桦甸市|