go的有缓冲chann和无缓冲chan的区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了go的有缓冲chann和无缓冲chan的区别相关的知识,希望对你有一定的参考价值。

参考技术A 有缓冲chan不容易阻塞
无缓冲chan是同步的,就是在一个协程里面塞(取),另外一个操作必须即刻执行否则就会阻塞

程序的执行是以栈的方式逐步执行的,如此就能知道什么时候会阻塞了!

Go中缓冲通道和非缓冲通道的测距有啥区别?

【中文标题】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 中加入&lt;-time.After(1),函数会突然阻塞,你会得到调度器将调度另一个例程的效果。

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

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

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

有这个调度器的解释https://rakyll.org/scheduler/。

【讨论】:

以上是关于go的有缓冲chann和无缓冲chan的区别的主要内容,如果未能解决你的问题,请参考以下文章

go缓冲区

Go中缓冲通道和非缓冲通道的测距有啥区别?

Go语言基础之并发 goroutine chan

c:=make(chan int) 和 c:=make(chan int,1) 有啥区别?

golang--Channel有无缓存区别,以及关闭原则

关于Go的Channel,Silce,Map