Go中缓冲通道和非缓冲通道的测距有啥区别?
Posted
技术标签:
【中文标题】Go中缓冲通道和非缓冲通道的测距有啥区别?【英文标题】:What are the differences between ranging over a buffered channel and non-buffered channel in Go?Go中缓冲通道和非缓冲通道的测距有什么区别? 【发布时间】:2018-04-15 15:50:30 【问题描述】:我正在尝试类似于以下模式的东西:
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()
)。因此我最终使用了非缓冲通道,以便等待响应的时间和生产者中处理数据的时间可以重叠,从而提高并发性。
【问题讨论】:
你正在观察 goroutine 调度器的效果。在发送循环中添加 time.Sleep(time.Second) 并观察会发生什么。 我建议您运行 go trace 工具并可视化跟踪。它将帮助您了解两个 go 例程是如何运行的。有关如何使用跟踪工具***.com/questions/32131339/the-go-1-5-trace-command,请参阅此答案 【参考方案1】:正如 Cerise Limón 已经说过的:这是运行时计划如何执行例程的影响。基本上,只要不阻塞或返回,go 例程就会运行。因此调用go sendFunc(10, c)
将一直执行,直到它阻塞或返回。如果你在sendFunc
中加入<-time.After(1)
,函数会突然阻塞,你会得到调度器将调度另一个例程的效果。
这是操场上的一个小例子: https://play.golang.org/p/99vJniOf3_
哪个更好的问题很难回答。免责声明:到目前为止,我还不是这方面的专家,但我想这是一种权衡。虽然较小的缓冲区减少了单个消息在缓冲区中停留的时间,但它会触发 go 例程的重新调度,这通常会花费一些时间。
另一方面,较大的缓冲区会增加通过缓冲区的消息延迟,但另一方面会提高吞吐量。此外,您还可以预先生成大量消息,如果您有一些对于一条或多条消息相同的静态开销(例如,请求单行输入与请求多行输入),这将很有用。
有这个调度器的解释https://rakyll.org/scheduler/。
【讨论】:
以上是关于Go中缓冲通道和非缓冲通道的测距有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章