2015-12-28 86 views
0

我在使用goroutines時遇到同步問題。我的程序輸出不可預知的結果。我檢查了文件和無緩衝的頻道,沒有辦法檢查是否所有的信息已經處理。我將這個問題簡化爲這個仍然演示問題的小演示代碼。很明顯,這不是Golang的問題,而是我的代碼。顯然,我沒有使用正確的併發模式。golang併發同步問題

問題是如何解決這個問題。如果可能的話,我不想關閉通道,也不想停止蜂巢門戶。它認爲如果我可以假設一旦所有的蜜蜂程序都完成了,現在蜂巢也完成了(這是我通過使用wg.Wait()來嘗試的)。

package main 

import(
    "fmt" 
    "sync" 
    "time" 
) 



func main() { 
    count := int64(0) 
    c := make(chan int64) 
    var wg sync.WaitGroup 

    // bees 
    for i:=0; i<5000;i++{ 
     wg.Add(1) 
     go func(in chan int64) { 
      defer wg.Done() 
      time.Sleep(100) 
      in <- 2 
     }(c) 
    } 

    // hive 
    go func() { 
     for out := range c { 
      count += out 
     } 
    }() 

    wg.Wait() 
    // bang! but why? 
    fmt.Println(count) 
} 

// every now and again the program prints out before it is finished 
// $ go run pattern1.go 
// 10000 
// $ go run pattern1.go 
// 9998 
// $ go run pattern1.go 
// 9998 
// $ go run pattern1.go 
// 10000 
// $ go run pattern1.go 
// 10000 
// $ go run pattern1.go 
// 9998 
+0

你在你的代碼的數據種族,請運行帶'-race'標誌的代碼(去運行/ build -race)。這將打印出有關數據競賽的信息。 – nussjustin

+0

如果「hive」循環沒有關閉'c',或者插入另一個計數器和同步原語,您無法確定是否已從'c'處理所有值。如果所有的goroutines都完成了,那麼關閉頻道有什麼意義呢? – JimB

+1

-race標誌必須在運行後但在文件名之前。文件名後面的任何內容都會傳遞給您的進程,但-race是一個編譯器標誌。 – nussjustin

回答

4

你永遠等待「蜂巢」循環來完成,所以有時你打印count值它完成之前。

這是最容易使用的WaitGroup信號時,在關閉通道,並阻止main的範圍內循環:

go func() { 
    wg.Wait() 
    close(c) 
}() 

for out := range c { 
    count += out 
} 

http://play.golang.org/p/jK24dtG2je