golang fifo 缓冲通道
Posted
技术标签:
【中文标题】golang fifo 缓冲通道【英文标题】:golang fifo buffered channel 【发布时间】:2016-08-30 04:14:19 【问题描述】:据我了解:当通道已满时,GO 中的缓冲通道不是 FIFO。 我的应用程序中需要这种行为(FIFO 行为)。 我怎样才能实现这种行为?有什么开源的吗? 在此先感谢
编辑: 有些人不喜欢这个问题,所以让我说得更清楚: 我的意思是当缓冲通道已满并且多个发送者被阻止时 在尝试将项目添加到频道时,它们将被释放的顺序 不是先进先出。你也可以阅读这个讨论:https://github.com/golang/go/issues/11506
是的,我一直在寻找实现该行为的第三方库。 抱歉没有说清楚。
【问题讨论】:
正如你刚才所说,这就是 Go 中通道的工作方式。您可以通过使用频道来实现这一点......对不起,但绝对是可怕的问题。 @evanmcdonnal 未指定在完整通道上阻止的发件人的执行顺序。问如何制作这个FIFO并不可怕。规范中没有任何内容表明您可以通过使用频道来实现这一点......问题的问题是它要求推荐一个软件包。 @KarrotKake 不,我认为它很清楚地说明了项目是按照发送顺序从频道中读取的,这意味着先进先出。 @evanmcdonnal 规范和内存模型文档没有说明发送时阻塞的 goroutines 的执行顺序。 我将问题编辑得更清楚。很抱歉从一开始就不是这样 【参考方案1】:Go 中的缓冲通道始终是 FIFO。规范清楚地说:
通道充当先进先出队列。
如果来自通道的值不是 FIFO,那么这是通道实现中的错误。
以下代码应始终按正确顺序打印 1、2、3、4:
package main
import (
"fmt"
"time"
)
func main()
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
go func()
ch <- 4
()
time.Sleep(time.Second)
for i := 0; i < 4; i++
fmt.Println(<-ch)
Playground link
请注意,当有多个并发发送者时,不保证先发送哪个值。如果有多个等待发送者并且有人从通道缓冲区中删除了一个元素(或者在无缓冲通道的情况下,尝试从通道接收),运行时将随机选择一个发送 goroutine。
例子:
package main
import (
"fmt"
"time"
)
func main()
ch := make(chan int, 2)
ch <- 1
go func()
ch <- 2
()
go func()
ch <- 3
()
time.Sleep(time.Second)
for i := 0; i < 3; i++
fmt.Println(<-ch)
Playground link
如果您多次运行此代码,您会看到输出有时会是 1、2、3 或 1、3、2。(这在操场上不起作用,因为输出已缓存)
【讨论】:
我的意思是在有多个发件人的情况下,不能保证第一个被阻止的发件人会第一个被释放。这就是我说“当通道已满时,GO 中的缓冲通道不是 FIFO”时的意思。无论如何,我正在寻找 Fifo 阻止发件人的实现。 @user3142398 如果你想要这个,你必须自己实现它。我不知道有什么包可以做到这一点。您可能可以使用队列和条件变量以及递增计数器进行发送,但它可能不是很有效。【参考方案2】:你可以使用链表。
容器/列表包 (https://golang.org/pkg/container/) 实现了一个可以用作队列的双向链表。也许,它还实现了 Heap,它允许您创建具有优先级的队列。总之,最简单的方法是链表IHMO:
queue := list.New()
queue.PushBack("Hello ") // Enqueue
queue.PushBack("world!")
for queue.Len() > 0
e := queue.Front() // First element
fmt.Print(e.Value)
queue.Remove(e) // Dequeue
【讨论】:
以上是关于golang fifo 缓冲通道的主要内容,如果未能解决你的问题,请参考以下文章
Golang:为啥增加缓冲通道的大小会消除我的 goroutine 的输出?