詳解Go語(yǔ)言中Goroutine退出機(jī)制的原理及使用_第1頁(yè)
詳解Go語(yǔ)言中Goroutine退出機(jī)制的原理及使用_第2頁(yè)
詳解Go語(yǔ)言中Goroutine退出機(jī)制的原理及使用_第3頁(yè)
詳解Go語(yǔ)言中Goroutine退出機(jī)制的原理及使用_第4頁(yè)
詳解Go語(yǔ)言中Goroutine退出機(jī)制的原理及使用_第5頁(yè)
已閱讀5頁(yè),還剩1頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第詳解Go語(yǔ)言中Goroutine退出機(jī)制的原理及使用}

WaitGroup可以理解為一個(gè)goroutine管理者。他需要知道有多少個(gè)goroutine在給他干活,并且在干完的時(shí)候需要通知他干完了,否則他就會(huì)一直等,直到所有的小弟的活都干完為止。我們加上WaitGroup之后,程序會(huì)進(jìn)行等待,直到它收到足夠數(shù)量的Done()信號(hào)為止。

WaitGroup可被調(diào)用的方法只有三個(gè):Add()、Done()、Wait()。通過(guò)這三個(gè)方法即可實(shí)現(xiàn)上述的功能,下面我們把源碼貼出。

func(wg*WaitGroup)Add(deltaint){

statep:=wg.state()

state:=atomic.AddUint64(statep,uint64(delta)32)

v:=int32(state32)//計(jì)數(shù)器

w:=uint32(state)//等待者個(gè)數(shù)。這里用uint32,會(huì)直接截?cái)嗔烁呶?2位,留下低32位

ifv0{

//Done的執(zhí)行次數(shù)超出Add的數(shù)量

panic("sync:negativeWaitGroupcounter")

ifw!=0delta0v==int32(delta){

//最開(kāi)始時(shí),Wait不能在Add之前被執(zhí)行

panic("sync:WaitGroupmisuse:AddcalledconcurrentlywithWait")

ifv0||w==0{

//計(jì)數(shù)器不為零,還有沒(méi)Done的。return

//沒(méi)有等待者。return

return

//所有g(shù)oroutine都完成任務(wù)了,但有g(shù)oroutine執(zhí)行了Wait后被阻塞,需要喚醒它

if*statep!=state{

//已經(jīng)到了喚醒階段了,就不能同時(shí)并發(fā)Add了

panic("sync:WaitGroupmisuse:AddcalledconcurrentlywithWait")

//清零之后,就可以繼續(xù)Add和Done了

*statep=0

for;w!=0;w--{

//喚醒

runtime_Semrelease(wg.sema,false)

func(wg*WaitGroup)Done(){

wg.Add(-1)

func(wg*WaitGroup)Wait(){

statep:=wg.state()

for{

state:=atomic.LoadUint64(statep)

v:=int32(state32)//計(jì)數(shù)器

w:=uint32(state)//等待者個(gè)數(shù)

ifv==0{

//如果聲明變量后,直接執(zhí)行Wait也不會(huì)有問(wèn)題

//下面CAS操作失敗,重試,但剛好發(fā)現(xiàn)計(jì)數(shù)器變成零了,安全退出

return

ifatomic.CompareAndSwapUint64(statep,state,state+1){

ifrace.Enabledw==0{

race.Write(unsafe.Pointer(wg.sema))

//掛起當(dāng)前的g

runtime_Semacquire(wg.sema)

//被喚醒后,計(jì)數(shù)器不應(yīng)該大于0

//大于0意味著Add的數(shù)量被Done完后,又開(kāi)始了新一波Add

if*statep!=0{

panic("sync:WaitGroupisreusedbeforepreviousWaithasreturned")

return

}

通過(guò)看源碼,我們可以知道,有些使用細(xì)節(jié)是需要注意的:

1.wg.Done()函數(shù)實(shí)際上實(shí)現(xiàn)的是wg.Add(-1),因此直接使用wg.Add(-1)是會(huì)造成同樣的結(jié)果的。在實(shí)際使用中要注意避免誤操作,使得監(jiān)聽(tīng)的goroutine數(shù)量出現(xiàn)誤差。

2.wg.Add()函數(shù)可以一次性加n。但是實(shí)際使用時(shí)通常都設(shè)為1。但是wg本身的counter不能設(shè)為負(fù)數(shù)。假設(shè)你在沒(méi)有Add到10以前,一次性wg.Add(-10),會(huì)出現(xiàn)panic!

packagemain

import(

"fmt"

"sync"

funcmain(){

varwgsync.WaitGroup//定義WaitGroup

arr:=[3]string{"a","b","c"}

for_,v:=rangearr{

wg.Add(1)//增加一個(gè)wait任務(wù)

gofunc(sstring){

deferwg.Done()//函數(shù)結(jié)束時(shí),通知此wait任務(wù)已經(jīng)完成

fmt.Println(s)

}(v)

wg.Add(-10)

//等待所有任務(wù)完成

wg.Wait()

panic:sync:negativeWaitGroupcounter

3.如果你的程序?qū)懙挠袉?wèn)題,出現(xiàn)了始終等待的waitgroup會(huì)造成死鎖。

packagemain

import(

"fmt"

"sync"

funcmain(){

varwgsync.WaitGroup//定義WaitGroup

arr:=[3]string{"a","b","c"}

for_,v:=rangearr{

wg.Add(1)//增加一個(gè)wait任務(wù)

gofunc(sstring){

deferwg.Done()//函數(shù)結(jié)束時(shí),通知此wait任務(wù)已經(jīng)完成

fmt.Println(s)

}(v)

wg.Add(1)

//等待所有任務(wù)完成

wg.Wait()

fatalerror:allgoroutinesareasleep-deadlock!

通過(guò)channel

第二種方法即是通過(guò)channel。具體寫(xiě)法如下:

packagemain

import"fmt"

funcmain(){

arr:=[3]string{"a","b","c"}

ch:=make(chanstruct{},len(arr))

for_,v:=rangearr{

gofunc(sstring){

fmt.Println(s)

ch-struct{}{}

}(v)

fori:=0;ilen(arr);i++{

}

需要注意的是,channel同樣會(huì)導(dǎo)致死鎖。如下方示例:

packagemain

import"fmt"

funcmain(){

arr:=[3]string{"a","b","c"}

ch:=make(chanstruct{},len(arr))

for_,v:=rangearr{

gofunc(sstring){

fmt.Println(s)

ch-struct{}{}

}(v)

fori:=0;ilen(arr);i++{

fatalerror:allgoroutinesareasleep-deadlock!

封裝

利用goroutine的這一特性,我們可以將waitGroup等方式封裝起來(lái),保證goroutine在主進(jìn)程結(jié)束時(shí)會(huì)繼續(xù)執(zhí)行完。封裝demo:

packagemain

import(

"fmt"

"sync"

typeWaitGroupWrapperstruct{

sync.WaitGroup

func(wg*WaitGroupWrapper)Wrap(ffunc(args...interface{}),args...interface{}){

wg.Add(1)

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論