何时使用缓冲通道?

时间:2013-02-27 13:33:52

标签: go

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

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)
}

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

5 个答案:

答案 0 :(得分:13)

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

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

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

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

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

  • occam jcsp 中使用了特殊的覆盖或有损形式的通道来修复进程周期(或循环)的特殊情况否则可能是死锁。通过编写覆盖goroutine缓冲区(example)也可以在Go中实现。

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

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

答案 1 :(得分:10)

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

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

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

拥有一个缓冲区允许调度程序在队列中存放作业,并仍然保持对用户输入(或网络流量,或其他)的响应,因为它不必在每次调度任务时工作者准备就绪时休眠。相反,它是关于它的业务,并相信工人在更安静的时期赶上来。

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

答案 2 :(得分:3)

只要还有空间,缓冲的频道对发送方都是非阻止的。这可以提高响应速度和吞吐量。

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

From Effective Go(带示例):&#34; A buffered channel can be used like a semaphore, for instance to limit throughput.&#34;

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

答案 3 :(得分:3)

如果频道的接收者总是慢于发送者,则最终会消耗任何大小的缓冲区。这将为您留下一个通道,可以像无缓冲通道一样暂停您的常规程序,因此您也可以使用无缓冲通道。

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

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

答案 4 :(得分:0)

这是一个很难的问题b / c程序是不正确的:它在收到一个goroutine的信号后退出,但是三个已经启动。缓冲频道也没有什么不同。

编辑:例如,这里有一些关于频道buffers的一般性讨论。还有一些exercise。和book chapter差不多。