单通道上Goroutine解锁的顺序

Jus*_*tin 9 channel go

Goroutines在频道上阻止的顺序是否决定了它们将解锁的顺序?我并不关心发送的消息的顺序(保证它们是有序的),而是Goroutines的顺序,它将解锁.

想象一下,ch在多个Goroutines(1,2和3)之间共享一个空的Channel ,每个Goroutine都试图接收一条消息ch.由于ch是空的,每个Goroutine都会阻止.当我发送消息时ch,Goroutine 1会先取消阻止吗?或者2或3可能会收到第一条消息?(反之亦然,Goroutines试图发送)

我有一个操场,似乎表明Goroutines阻止的顺序是它们被解锁的顺序,但我不确定这是否是一个未定义的行为,因为实现.

Ric*_*777 4

这是一个好问题——它涉及到并发设计时的一些重要问题。正如已经说过的,根据当前的实现,您的具体问题的答案是基于 FIFO 的。它不太可能有所不同,除非实施者出于某种原因认为后进先出法更好。

但并不能保证因此,您应该避免创建依赖于特定实现的代码。

更广泛的问题涉及非决定论公平饥饿

也许令人惊讶的是,基于 CSP 的系统中的非确定性并不是来自并行发生的事情。因为并发所以有可能,但又不是因为并发才可能。相反,当做出选择时,就会出现非决定论。在 CSP 的形式代数中,这是通过数学建模的。幸运的是,您不需要了解数学就可以使用 Go。但形式上,两个 goroutine 代码并行执行,只要消除所有选择,结果仍然是确定性的。

selectGo 允许通过在 goroutine 之间共享的通道末端显式和隐式引入非确定性的选择。如果您有点对点(一个读者,一个作者)通道,则不会出现第二种。因此,如果它在特定情况下很重要,您就可以做出设计选择。

公平饥饿通常是同一枚硬币的两面。饥饿是动态问题之一(以及死锁、活锁和竞争条件),它可能会导致性能不佳,更有可能导致错误的行为。这些动态问题是不可测试的(更多内容在此),需要进行一些级别的分析来解决。显然,如果系统的一部分由于缺乏对某些资源的访问而没有响应,那么就需要在管理这些资源时更加公平。

由于当前的 FIFO 行为,对通道端的共享访问很可能提供一定程度的公平性,并且这可能看起来足够了。但如果您希望得到保证(无论实现的不确定性如何),可以select在数组中使用一个和一组点对点通道。公平索引很容易实现,方法是始终按照将最后选择的索引放在堆的底部的顺序来优先选择它们。该解决方案可以保证公平性,但可能会带来较小的性能损失。

(旁白:请参阅“Wot No Chickens”,了解英国坎特伯雷的研究人员关于 Java 虚拟机中的公平性缺陷的一个有点有趣的发现 - 该缺陷从未得到纠正!)