在Go語(yǔ)言中,如果使用goroutine,經(jīng)常需要阻塞主進(jìn)程來等待goroutine的結(jié)束,我們有以下幾種方式來實(shí)現(xiàn)
使用channel實(shí)現(xiàn)
package main
import (
"log"
"time"
)
func main() {
ch := make(chan int, 1)
go func() {
log.Println("wait 3s...")
time.Sleep(3 * time.Second)
ch<-1
}()
<-ch
}
使用waitGroup實(shí)現(xiàn)
waiteGroup顧名思義,是等待一組行為執(zhí)行結(jié)束,利用wg.Add()來添加group,利用wg.Done或wg.Add(-1)來移除,wg.Wait()一直阻塞直到group完全釋放
package main
import (
"log"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
for i:=0;i<5;i++{
wg.Add(1)
go func(n int) {
defer wg.Done()
time.Sleep(3 * time.Second)
log.Println(n)
}(i)
}
wg.Wait()
}
NSQ源碼中使用示例
此處代碼是NSQ中封裝的WaitGroupWrapper,通過Wrap方法可以方便的添加需要執(zhí)行的goroutine,并阻塞主進(jìn)程
package util
import (
"sync"
)
type WaitGroupWrapper struct {
sync.WaitGroup
}
func (w *WaitGroupWrapper) Wrap(cb func()) {
w.Add(1)
go func() {
cb()
w.Done()
}()
}
阻塞os信號(hào)
如果進(jìn)程被kill,很多時(shí)候我們不能立即退出,需要善后,處理類似內(nèi)存信息持久化等信息。
那么在Go中如何優(yōu)雅的退出進(jìn)程,下面這段代碼通過捕捉os信號(hào)后,進(jìn)行退出前的異常處理
signalChan := make(chan os.Signal, 1)
// 捕捉 Ctrl+c 和 kill 信號(hào),寫入signalChan
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
// 此處執(zhí)行處理邏輯
nsqd.Main()
// signalChan阻塞進(jìn)程
<-signalChan
// 捕捉信號(hào)后在Exit函數(shù)中處理信息,例如內(nèi)存持久化等信息防止丟失
nsqd.Exit()