Golang - 异步func中缓冲通道的范围可以同步吗?

时间:2017-11-03 00:55:53

标签: go channel

我正尝试类似以下模式:

func sendFunc(n int, c chan int) {
    for i := 0; i < n; i++ {
        c <- i
        fmt.Println("Pushed")
    }
    close(c)
}

func main() {
    c := make(chan int, 10)
    go sendFunc(10, c)
    // Receive from the channel
    for i := range c {
        fmt.Println(i)
    }
}

输出似乎是同步的,如下所示:

Pushed
Pushed
Pushed
Pushed
Pushed
Pushed
Pushed
Pushed
Pushed
Pushed
0
1
2
3
4
5
6
7
8
9

这是否意味着for循环的范围实际上是同步接收数据?

但是,如果我将缓冲的频道更改为非缓冲频道:

c := make(chan int)

结果似乎是异步的:

Pushed
0
1
Pushed
Pushed
2
3
Pushed
Pushed
4
5
Pushed
Pushed
6
7
Pushed
Pushed
8
9
Pushed

哪一个更好? (性能差异怎么样?)

更新

所以我的场景是:在receiverFunc中,每次从sendFunc()接收到新数据时都会发出请求,结果显示调度程序在所有数据都已发送到通道之前不会开始接收(给定具有足够缓冲空间的缓冲通道)。因此,我最终使用了非缓冲通道,以便等待响应的时间和sendFunc()中处理数据的时间可以重叠,从而提供更好的性能。

1 个答案:

答案 0 :(得分:0)

正如CeriseLimón已经说过的那样:这是运行时调度如何进行例程的结果。基本上只要它不阻塞或返回就运行go例程。因此调用go sendFunc(10, c)将一直执行,直到它阻塞或返回。如果在<-time.After(1)中放置sendFunc,该函数将突然阻塞,您将获得调度程序将安排另一个例程的效果。

这是操场上的一个小例子: https://play.golang.org/p/99vJniOf3_

哪一个更好的问题很难回答。免责声明:到目前为止,我还不是这方面的专家,但我想这是一个权衡。虽然较小的缓冲区减少了单个消息留在缓冲区中的时间,但它会触发对例程的重新调度,这通常会花费一些时间。

另一方面,较大的缓冲区可以通过缓冲区增加消息延迟,但另一方面可以提高吞吐量。此外,您可以预先生成大量消息,如果您有一些静态开销对于一条或多条消息是相同的(例如,请求单行输入与请求多行输入),这可能很有用。

对调度程序https://rakyll.org/scheduler/进行此解释。