今天遇到一个问题(应该算是坑吧):golang
在Goroutine中退出时defer
调用RPC的Close函数, 可是server老是提示网络非正常退出.安全
最终发现是Goroutine退出时调用Close可能致使阻塞, 阻塞致使Goroutine切换到main.网络
main 退出后程序就终止了.函数
我构造了一个相似的例子:fetch
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清理工做所有完成.ui
更好的等待Goroutine完成的方法是用sync.WaitGroup
:google
// This example fetches several URLs concurrently, // 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/#WaitGroupurl