我是Go的新手,我试图了解并发模式。当我运行以下代码时,我有时会得到预期的结果(从0到9999的完整数组)。其他时候我只是得到一个"那就是"显示时间的消息。有时我只是在封闭频道发送#34;"错误。这里可能出现什么问题?
package main
import (
"fmt"
"time"
"sync"
)
func JobsDispatcher(in chan int, data []int){
for _, value := range data{
in<-value
}
close(in)
}
func Worker(in chan int, out chan int, wg *sync.WaitGroup){
wg.Add(1)
for{
inMsg, ok := <-in
if !ok{
wg.Done()
return
}
out <- inMsg
}
}
func PrintInt(out chan int){
for {
outMsg, ok := <-out
if !ok{
fmt.Println("")
fmt.Println("That's it")
return
}
fmt.Println(outMsg)
}
}
func ParallelPrint(data []int){
var wg sync.WaitGroup
in := make(chan int)
out := make(chan int)
parallelStartTime := time.Now()
go JobsDispatcher(in, data)
for i:=0;i<5;i++{
go Worker(in,out,&wg)
}
go func(){
wg.Wait()
close(out)
}()
PrintInt(out)
fmt.Println(time.Since(parallelStartTime))
}
func main(){
data := make([]int,0)
for i:=0;i<10000;i++{
data = append(data, i)
}
ParallelPrint(data)
}
答案 0 :(得分:5)
这个很容易。这就是为什么你从来没有在goroutine中使用WaitGroup的Add。在开始goroutine之前一定要打电话。
问题是你堆积了一堆goroutine然后立即打电话给Wait。 Go不承诺在任何特定时间运行你的goroutine,就像POSIX或Windows线程不能保证一样。
因此,在这种情况下,您为调度程序提供了一堆将来运行的goroutine,但它决定先完成代码。因此它在执行wg.Wait()
之前运行close(out)
和wg.Add()
。
答案 1 :(得分:3)
你想在goroutine之外调用wg.Add
- 即:
for i:=0;i<5;i++{
wg.Add(1) // Here, not inside Worker()
go Worker(in,out,&wg)
}
否则,它可以添加所有工作人员,在任何工作人员调用wg.Wait
之前点击wg.Add
,这将立即返回,然后关闭频道。