2015-12-28 56 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