何时使用缓冲通道?

Dan*_*nte 22 go

缓冲通道的用例有哪些?如果我想要多个并行动作,我可以使用默认的同步通道eq.

package main
import "fmt"
import "time"

func longLastingProcess(c chan string) {
    time.Sleep(2000 * time.Millisecond)
    c <- "tadaa"
}

func main() {
    c := make(chan string)
    go longLastingProcess(c)
    go longLastingProcess(c)
    go longLastingProcess(c)
    fmt.Println(<- c)
}
Run Code Online (Sandbox Code Playgroud)

增加缓冲区大小的实际情况是什么?

Ric*_*777 13

通常,由于性能原因,在信道中缓冲是有益的.

如果程序是使用事件流或数据流方法设计的,则通道提供事件在一个进程和另一个进程之间传递的方法(我使用与Tony Hoare的通信顺序进程(CSP)相同的术语进程) ,即.有效地与goroutine同义).

  • 有时程序需要其组件保持锁步同步.在这种情况下,需要无缓冲的通道.

  • 否则,向通道添加缓冲通常是有益的.这应该被视为一个优化步骤(如果没有设计出来,死锁仍然可能).

  • 通过使用具有小缓冲器的通道(示例),可以实现新颖的节流结构.

  • occamjcsp中使用了特殊的覆盖或有损形式的通道来修复进程的循环(或循环)的特殊情况,否则可能会死锁.通过编写覆盖goroutine缓冲区(示例),这也可以在Go中实现.

你永远不应该只是添加缓冲来修复死锁.如果您的程序死锁,那么从零缓冲开始并通过依赖关系思考就更容易修复.然后在您知道它不会死锁时添加缓冲.

你可以在构图上构造goroutines - 也就是说,goroutine本身可以包含goroutines.这是CSP的一项功能,极大地提高了可扩展性.在将组的外部用途设计为独立组件时,一组goroutine之间的内部通道不受关注.该原理可以在越来越大的规模上重复应用.

  • 它们也可用于确保goroutine退出,例如在`time.After`中使用它,无论客户端是否在等待值,它都可以发送和返回.缓冲也被例如`os/signal`包的客户端使用,因为API无法阻止通知. (2认同)

mac*_*021 11

给出一个稍微更具体的用例:

假设您希望通道表示任务队列,以便任务计划程序可以将作业发送到队列,并且工作线程可以通过在通道中接收作业来使用作业.

进一步假设,虽然通常您希望及时处理每个作业,但是完成任务所需的工作时间比调度程序安排任务所需的时间长.

具有缓冲区允许调度程序将作业存储在队列中并仍然保持对用户输入(或网络流量等)的响应,因为它不必在每次调度任务时工作者准备好之前休眠.相反,它是关于它的业务,并相信工人在更安静的时期赶上.

如果你想要一个更加复杂的例子来处理特定的软件,那么我会看到我能做什么,但我希望这能满足你的需求.


Bil*_*lly 11

如果通道的接收方总是比发送方慢,则任何大小的缓冲区最终都将被消耗。这将为您留下一个与无缓冲通道一样频繁地暂停您的 go 例程的通道,因此您不妨使用无缓冲通道。

如果接收器通常比发送器快(除了偶尔的突发),则缓冲通道可能会有所帮助,并且缓冲区应设置为典型突发的大小,您可以在运行时通过测量得出该大小。

作为缓冲通道的替代方案,最好仅通过通道发送数组或包含数组的结构来处理突发/批量。


Tho*_*ler 5

只要还有空间,缓冲通道就不会阻塞发送方。这可以提高响应能力和吞吐量。

在一个缓冲通道上发送多个项目可确保按发送顺序处理它们。

来自 Effective Go(示例):“缓冲通道可以像信号量一样使用,例如限制吞吐量。

一般来说,信道使用的用例和模式有很多,所以这不是一个令人筋疲力尽的答案。


zzz*_*zzz 0

这是一个难题,因为程序不正确:它在收到来自一个 goroutine 的信号后退出,但启动了三个 goroutine。缓冲通道也没有什么不同。

编辑:例如,这里有一些关于通道缓冲区的一般讨论。还有一些锻炼。还有一本书的章节也有同样的内容。