Go Routines有时可以工作,有时会产生密切的通道错误

时间:2017-08-15 17:55:06

标签: go concurrency goroutine

我是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)
}

2 个答案:

答案 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,这将立即返回,然后关闭频道。