英文:
When to use a buffered channel?
问题
增加缓冲区大小的实际用例是什么?
英文:
What are the uses cases for buffered channels ? If i want multiple parallel actions i could just use the default, synchronous channel 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)
}
What would be the practical cases for increasing the buffer size ?
答案1
得分: 21
为了给出一个稍微具体一点的用例:
假设你想让你的通道表示一个任务队列,这样一个任务调度器就可以将任务发送到队列中,而一个工作线程可以通过在通道中接收任务来消费它。
进一步假设,尽管通常你希望每个任务都能及时处理,但工作线程完成任务所需的时间比调度器调度任务所需的时间更长。
有一个缓冲区允许调度器将任务放入队列中,并且仍然能够对用户输入(或网络流量等)保持响应,因为它不必在每次调度任务时都等待工作线程准备好。相反,它继续进行自己的工作,并相信工作线程会在较为安静的时期赶上进度。
如果你想要一个更具体的例子,涉及到特定的软件,那么我会尽力满足你的需求。
英文:
To give a single, slightly-more-concrete use case:
Suppose you want your channel to represent a task queue, so that a task scheduler can send jobs into the queue, and a worker thread can consume a job by receiving it in the channel.
Suppose further that, though in general you expect each job to be handled in a timely fashion, it takes longer for a worker to complete a task than it does for the scheduler to schedule it.
Having a buffer allows the scheduler to deposit jobs in the queue and still remain responsive to user input (or network traffic, or whatever) because it does not have to sleep until the worker is ready each time it schedules a task. Instead, it goes about its business, and trusts the workers to catch up during a quieter period.
If you want an EVEN MORE CONCRETE example dealing with a specific piece of software then I'll see what I can do, but I hope this meets your needs.
答案2
得分: 16
通常,通道中的缓冲对于性能来说是有益的。
如果一个程序使用事件流或数据流的方式设计,通道提供了事件在一个进程和另一个进程之间传递的方式(我在这里使用“进程”一词的意思与Tony Hoare的“通信顺序进程”(CSP)中的意思相同,即与“goroutine”基本上是同义词)。
-
有时候程序需要保持其组件的同步。在这种情况下,需要使用无缓冲通道。
-
否则,通常将缓冲添加到通道中是有益的。这应该被视为一种优化步骤(如果没有设计好,仍然可能发生死锁)。
-
使用小缓冲区的通道可以实现新颖的节流结构(示例)。
-
在occam和jcsp中使用特殊的覆盖或有损形式的通道来修复循环进程(或循环)的特殊情况,否则可能会发生死锁。在Go中,也可以通过编写一个覆盖的goroutine缓冲区来实现这一点(示例)。
永远不要仅仅为了解决死锁而添加缓冲。如果你的程序发生死锁,通过从零缓冲开始并思考依赖关系来修复它会更容易。然后在确定不会发生死锁时再添加缓冲。
你可以以组合的方式构建goroutines - 也就是说,一个goroutine本身可以包含其他goroutines。这是CSP的一个特性,并且极大地提高了可扩展性。当设计将一组goroutines作为一个自包含组件的外部使用时,不关心这些goroutines之间的内部通道。这个原则可以在不断扩大的规模上重复应用。
英文:
Generally, buffering in channels is beneficial for performance reasons.
If a program is designed using an event-flow or data-flow approach, channels provide the means for the events to pass between one process and another (I use the term process in the same sense as in Tony Hoare's Communicating Sequential Processes (CSP), ie. effectively synonymous with the goroutine).
-
There are times when a program needs its components to remain in lock-step synchrony. In this case, unbuffered channels are required.
-
Otherwise, it is typically beneficial to add buffering to the channels. This should be seen as an optimisation step (deadlock may still be possible if not designed out).
-
There are novel throttle structures made possible by using channels with small buffers (example).
-
There are special overwriting or lossy forms of channels used in occam and jcsp for fixing the special case of a cycle (or loop) of processes that would otherwise probably deadlock. This is also possible in Go by writing an overwriting goroutine buffer (example).
You should never add buffering merely to fix a deadlock. If your program deadlocks, it's far easier to fix by starting with zero buffering and think through the dependencies. Then add buffering when you know it won't deadlock.
You can construct goroutines compositionally - that is, a goroutine may itself contain goroutines. This is a feature of CSP and benefits scalability greatly. The internal channels between a group of goroutines are not of interest when designing the external use of the group as a self-contained component. This principle can be applied repeatedly at increasingly-larger scales.
答案3
得分: 11
如果通道的接收者始终比发送者慢,任何大小的缓冲区最终都会被消耗完。这将使您得到一个与无缓冲通道一样频繁暂停您的Go例程的通道,因此最好使用无缓冲通道。
如果接收者通常比发送者快,除了偶尔的突发情况,缓冲通道可能会有所帮助,缓冲区的大小应设置为典型突发情况的大小,您可以通过运行时测量得到。
作为缓冲通道的替代方案,最好只发送一个包含数组或结构的数组到通道中以处理突发/批处理情况。
英文:
If the receiver of the channel is always slower than sender a buffer of any size will eventually be consumed. That will leave you with a channel that pauses your go routine as often as a unbuffered channel so you might as well use an unbuffered channel.
If the receiver is typically faster than the sender except for an occasional burst a buffered channel may be helpful and the buffer should be set to the size of the typical burst which you can arrive at by measurement at runtime.
As an alternative to a buffered channel it may better to just send an array or a struct containing an array over the channel to deal with bursts/batches.
答案4
得分: 6
缓冲通道对于发送者来说是非阻塞的,只要还有空间。这可以提高响应性和吞吐量。
在一个缓冲通道上发送多个项目可以确保它们按照发送的顺序进行处理。
根据《Effective Go》(附带示例):“缓冲通道可以像信号量一样使用,例如用于限制吞吐量。”
总的来说,通道的使用有许多用例和模式,所以这并不是一个详尽的答案。
英文:
Buffered channels are non-blocking for the sender as long as there's still room. This can increase responsiveness and throughput.
Sending several items on one buffered channel makes sure they are processed in the order in which they are sent.
From Effective Go (with example): "A buffered channel can be used like a semaphore, for instance to limit throughput."
In general, there are many use-cases and patterns of channel usage, so this is not an exhausting answer.
答案5
得分: 0
这是一个难题,因为程序是错误的:它在接收到一个goroutine的信号后退出,但是有三个goroutine被启动。对通道进行缓冲使得它没有任何区别。
编辑:例如,这里有一些关于通道缓冲的一般讨论。还有一些练习。以及一本关于同样主题的书的章节。
英文:
It's a hard question b/c the program is incorrect: It exits after receiving a signal from one goroutine, but three were started. Buffering the channel makes it no different.
EDIT: For example, here is a bit of general discussion about channel buffers. And some exercise. And a book chapter about the same.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论