今天遇到一个问题(应该算是坑吧):
在Goroutine中退出时defer
调用RPC的Close函数, 但是server总是提示网络非正常退出.
最终发现是Goroutine退出时调用Close可能导致阻塞, 阻塞导致Goroutine切换到main.
main 退出后程序就终止了.
我构造了一个类似的例子:
package main
import (
"log"
"time"
)
func worker(quit <-chan bool) {
defer func() {
// 如果被调用函数内部可能阻塞的话
// 将不能保证被完全执行
time.Sleep(time.Second)
log.Println("worker clean up")
}()
for {
select {
case <-quit:
log.Println("worker quit ...")
return
default:
}
}
}
func main() {
quit := make(chan bool)
go worker(quit)
quit <- true
}
我目前想到的安全做法是: 再设置一个done管道, 在main
函数中阻塞等待Goroutine清理工作全部完成.
更好的等待Goroutine完成的方法是用sync.WaitGroup
:
"http://www.golang.org/",
// using a WaitGroup to block until all the fetches are complete.
func ExampleWaitGroup() {
var wg sync.WaitGroup
var urls = []string{
"http://www.golang.org/",
"http://www.google.com/",
"http://www.somestupidname.com/",
}
for _, url := range urls {
// Increment the WaitGroup counter.
wg.Add(1)
// Launch a goroutine to fetch the URL.
go func(url string) {
// Decrement the counter when the goroutine completes.
defer wg.Done()
// Fetch the URL.
http.Get(url)
}(url)
}
// Wait for all HTTP fetches to complete.
wg.Wait()
}
关于sync.WaitGroup
文档请参考: http://golang.org/pkg/sync/#WaitGroup
有疑问加站长微信联系(非本文作者)