Go 中缓冲通道和非缓冲通道之间的测距有什么区别?
What are the differences between ranging over a buffered channel and non-buffered channel in Go?
我正在尝试类似于以下模式的操作:
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
为什么它的行为不同?
已更新
所以我的场景是:每次从生产者接收到新数据时,接收者都会发出请求,结果显示调度程序直到所有数据都发送到通道后才会开始接收(给定具有足够 space 的缓冲通道),除非生产者暂停(例如通过调用 time.sleep()
)。因此,我最终使用了非缓冲通道,这样等待响应的时间和生产者处理数据的时间可以重叠,从而提高并发性。
正如 Cerise Limón 所说:这是 运行 时间表如何成为例行公事的结果。基本上一个 go 例程是 运行 只要它不阻塞或 returns。因此调用 go sendFunc(10, c)
将执行直到它阻塞或 returns。如果你在 sendFunc
中放置一个 <-time.After(1)
,函数会突然阻塞,你会产生调度程序将调度另一个例程的效果。
这是操场上的一个小例子:
https://play.golang.org/p/99vJniOf3_
哪个更好,这个问题很难回答。免责声明:到目前为止,我不是这方面的专家,但我想这是一种权衡。虽然较小的缓冲区会减少单个消息在缓冲区中停留的时间,但它会触发重新安排 go routines,这通常会花费一些时间。
另一方面,较大的缓冲区会增加通过缓冲区的消息延迟,但另一方面会提高吞吐量。您还可以预先生成很多消息,如果您有一些对于一条或多条消息相同的静态开销(例如,请求单行输入与请求多行输入),这会很有用。
有这个调度器的解释https://rakyll.org/scheduler/。
我正在尝试类似于以下模式的操作:
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
为什么它的行为不同?
已更新
所以我的场景是:每次从生产者接收到新数据时,接收者都会发出请求,结果显示调度程序直到所有数据都发送到通道后才会开始接收(给定具有足够 space 的缓冲通道),除非生产者暂停(例如通过调用 time.sleep()
)。因此,我最终使用了非缓冲通道,这样等待响应的时间和生产者处理数据的时间可以重叠,从而提高并发性。
正如 Cerise Limón 所说:这是 运行 时间表如何成为例行公事的结果。基本上一个 go 例程是 运行 只要它不阻塞或 returns。因此调用 go sendFunc(10, c)
将执行直到它阻塞或 returns。如果你在 sendFunc
中放置一个 <-time.After(1)
,函数会突然阻塞,你会产生调度程序将调度另一个例程的效果。
这是操场上的一个小例子: https://play.golang.org/p/99vJniOf3_
哪个更好,这个问题很难回答。免责声明:到目前为止,我不是这方面的专家,但我想这是一种权衡。虽然较小的缓冲区会减少单个消息在缓冲区中停留的时间,但它会触发重新安排 go routines,这通常会花费一些时间。
另一方面,较大的缓冲区会增加通过缓冲区的消息延迟,但另一方面会提高吞吐量。您还可以预先生成很多消息,如果您有一些对于一条或多条消息相同的静态开销(例如,请求单行输入与请求多行输入),这会很有用。
有这个调度器的解释https://rakyll.org/scheduler/。