Go Routines 有时有效,有时会出现关闭通道错误

Go Routines sometimes work, sometimes gives close channel error

我是 Go 新手,正在尝试了解并发模式。当我 运行 下面的代码时,我有时会得到预期的结果(从 0 到 9999 的完整数字数组)。其他时候我只是收到一条显示时间的 "That's it" 消息。有时我只会收到 "Sending on closed channel" 错误。这里可能出了什么问题?

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

这个很简单。这就是为什么你从不在 goroutine 中使用 WaitGroup 的 Add 。始终在启动 goroutine 之前调用它。

问题是你堆积了一堆 goroutine,然后立即调用 Wait。 Go 不承诺 运行 你的 goroutines 在任何特定时间,就像 POSIX 或 Windows 线程不是 gua运行teed.

所以,在这种情况下,你给了调度器一堆 goroutines 到 运行 以后,但它决定先完成你的代码。所以它 运行 wg.Wait()close(out) 在做 wg.Add().

之前

您想在 wg.Add goroutine 之外调用 - 即:

for i:=0;i<5;i++{
    wg.Add(1)    // Here, not inside Worker()
    go Worker(in,out,&wg)
}

否则,它可以添加所有工人,在任何工人呼叫wg.Add之前点击wg.Wait,这将立即return,然后关闭通道。