Golang 缓冲通道的 FIFO 实现

4
据我了解:在Go语言中,当通道已满时缓冲通道不是FIFO。
我需要在我的应用程序中实现这种行为(FIFO行为)。
如何实现这种行为? 有没有任何开源库可以实现这一点?
提前感谢。编辑:
有些人不喜欢这个问题,所以让我更清楚一些:
我指的是当缓冲通道已满且多个发送器被阻塞时,尝试向通道添加项目的顺序
不是FIFO顺序。您还可以阅读此讨论:https://github.com/golang/go/issues/11506
所以,是的,我正在寻找一个第三方库来实现这种行为。
抱歉没有表述清楚。

正如你刚才所说,这就是 Go 语言中的通道工作原理。你可以通过使用通道来实现这一点... 抱歉,但这个问题真的太糟糕了。 - evanmcdonnal
1
@evanmcdonnal 发送者在被阻塞的满通道上的执行顺序是未指定的。询问如何使其先进先出并不可怕。规范中没有任何说明可以通过使用通道来实现这一点...该问题的问题在于它要求推荐软件包。 - Charlie Tumahai
1
@KarrotKake,我认为很明显已经说明了项目是按照发送顺序从通道中读取的,这意味着先进先出。 - evanmcdonnal
@evanmcdonnal 规范和内存模型文档没有说明被阻塞在发送操作上的goroutine的执行顺序。 - Charlie Tumahai
我编辑了问题,使之更加清晰。很抱歉一开始没有做到这一点。 - Amit Shani
2个回答

16

在Go中,带缓存的通道始终是先进先出的。规范明确指出:

通道充当先进先出队列。

如果从通道中传出的值不是先进先出的,则这是通道实现中的错误。

以下代码应始终以正确顺序打印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 链接

请注意,当存在多个并发发送者时,并不能保证哪个值会被先发送。如果有多个等待发送者,并且有人从通道缓冲区中删除一个元素(或在无缓冲通道的情况下尝试从通道接收),则运行时将随机选择其中一个发送 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链接

如果您运行此代码多次,您会发现输出有时会是1、2、3或1、3、2。(在Playground中无法运行,因为输出被缓存)


我的意思是,在存在多个发送者的情况下,没有保证第一个被阻塞的发送者会第一个被释放。这就是我所说的“当通道已满时,GO中的缓冲通道不是FIFO”的意思。无论如何,我正在寻找一种实现可以对被阻塞的发送者进行Fifo排序。 - Amit Shani
2
如果你想要这个功能,你必须自己实现。我不知道有任何包可以做到这一点。你可能可以使用队列和条件变量来进行发送计数,但这可能不是非常高效的方法。 - nussjustin

3
你可以使用链表。
container/list包(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
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接