Go中在缓冲通道和非缓冲通道上测距有什么区别

  • 本文关键字:通道 缓冲 区别 Go 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

如果我将缓冲通道更改为非缓冲通道:

c := make(chan int)

结果似乎是异步的:

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

为什么它的行为不同?

更新

因此,我的场景是:在接收器中,每次从生产者接收到新数据时都会发出请求,结果显示,除非生产者暂停(例如,通过调用time.sleep()),否则调度器直到所有数据都发送到信道(给定一个有足够空间的缓冲信道)才开始接收。因此,我最终使用了非缓冲通道,这样等待响应的时间和在生产者中处理数据的时间可以重叠,从而获得更好的并发性。

正如Cerise Limón已经指出的:这是运行时调度如何执行例程的影响。基本上,go例程是运行的,只要它不阻塞或返回。因此,调用go sendFunc(10, c)将执行,直到它阻塞或返回。如果你在sendFunc中放入一个<-time.After(1),函数会突然阻塞,你会得到调度器安排另一个例程的效果。

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

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

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

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

最新更新