26

缓冲通道的用例是什么?如果我想要多个并行操作,我可以使用默认的同步通道 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)
}

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

4

5 回答 5

17

通常,出于性能原因,通道中的缓冲是有益的。

如果一个程序是使用事件流或数据流方法设计的,通道为事件在一个进程和另一个进程之间传递提供了手段(我使用的术语进程与托尼霍尔的通信顺序进程(CSP)中的含义相同,即有效地与goroutine同义)。

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

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

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

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

你不应该仅仅为了修复死锁而添加缓冲。如果您的程序死锁,从零缓冲开始并考虑依赖关系会更容易修复。然后当你知道它不会死锁时添加缓冲。

您可以组合地构造 goroutines - 也就是说,goroutines 本身可能包含 goroutines。这是 CSP 的一个特性,极大地有利于可扩展性。在将组的外部使用设计为自包含组件时,一组 goroutine 之间的内部通道并不重要。这个原则可以在越来越大的范围内重复应用。

于 2013-02-28T19:54:31.133 回答
16

给出一个更具体的用例:

假设您希望您的通道代表一个任务队列,以便任务调度程序可以将作业发送到队列中,并且工作线程可以通过在通道中接收作业来使用它。

进一步假设,尽管通常您希望及时处理每个作业,但工作人员完成任务所需的时间比调度程序安排任务所需的时间要长。

拥有缓冲区允许调度程序将作业存放在队列中,并且仍然保持对用户输入(或网络流量或其他任何内容)的响应,因为它不必在每次调度任务时工作人员准备好之前休眠。取而代之的是,它开展自己的业务,并相信工人会在较安静的时期赶上来。

如果你想要一个更具体的例子来处理特定的软件,那么我会看看我能做什么,但我希望这能满足你的需要。

于 2013-02-27T20:04:25.720 回答
6

只要还有空间,缓冲通道对发送方来说是非阻塞的。这可以提高响应能力和吞吐量。

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

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

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

于 2013-02-27T14:09:18.883 回答
6

如果通道的接收者总是比发送者慢,那么任何大小的缓冲区最终都会被消耗掉。这将为您留下一个通道,该通道可以像无缓冲通道一样频繁地暂停您的 goroutine,因此您不妨使用无缓冲通道。

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

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

于 2017-02-14T23:46:14.250 回答
0

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

编辑:例如,这里有一些关于通道缓冲区的一般性讨论。并进行一些锻炼。和一本书的章节差不多。

于 2013-02-27T13:38:58.120 回答