今天遇到一個問題(應該算是坑吧):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