单个通道上有多个接收器。谁获得数据?

问题描述 投票:0回答:3

无缓冲的通道会阻塞接收器,直到通道上有数据可用为止。我不清楚同一通道上的多个接收器(例如使用 goroutine 时)的阻塞行为如何。我确信只要该通道上没有发送数据,它们都会阻塞。
但是,一旦我向该通道发送单个值会发生什么?哪个接收器/协程将获取数据并因此解锁?他们全部?第一个排队?随机?

go blocking channel
3个回答
18
投票

一个随机(非确定性)的人将收到它。

查看语言规范

“select”语句的执行分几个步骤进行:

  1. 对于语句中的所有情况,接收操作的通道操作数以及发送的通道和右侧表达式 输入时,语句按源顺序仅计算一次 “选择”语句。结果是一组接收通道 from 或 send to,以及要发送的相应值。任意一侧 无论哪种情况(如果有),该评估都会产生影响 选择通信操作进行。表达式关于 RecvStmt 的左侧带有短变量声明或 作业尚未评估。
  2. 如果一个或多个通信可以继续进行,则通过统一的伪随机选择来选择一个可以继续进行的通信。 否则,如果存在默认情况,则选择该情况。如果有 没有默认情况下,“select”语句会阻塞,直到至少一个 的通信可以继续进行。
  3. 除非选择的情况是默认情况,否则执行相应的通信操作。
  4. 如果选定的情况是带有短变量声明或赋值的 RecvStmt,则左侧表达式为 评估并分配接收到的值(或多个值)。
  5. 执行所选案例的语句列表。

1
投票

如果程序允许多个 goroutine 在单个通道上接收,则发送者正在广播。每个接收器应该同样能够处理数据。因此,go 运行时使用什么机制来决定众多 goroutine 接收器中的哪一个将运行并不重要。但如果通道未缓冲,则只会为每个发送的项目运行一个。

另请参阅:https://github.com/golang/go/issues/247,尤其是用户 josef.svenningsson 的推荐:

如果没有指定顺序,则可以自由实施 让一个进程完全挨饿,我认为没有人会这样做 高兴。某种公平保证对于 以确保所有 goroutine 都可以尝试进行评估。 所以,这不是能够控制顺序的问题 事情正在发生。我担心的是有些 goroutine 可能永远不会得到 如果接收者之间的顺序未定义,则有机会完成其工作。


0
投票

已经有一些对此进行了讨论

但是Go内存模型中所确定的是,它最多只是其中之一。

特定通道上的每个发送都与来自该通道的相应接收相匹配,通常在不同的 goroutine 中。

这并不像我想要的那么清晰,但稍后他们给出了信号量实现的示例

var limit = make(chan int, 3)

func main() {
    for _, w := range work {
        go func(w func()) {
            limit <- 1
            w()
            // if it were possible for more than one channel to receive
            // from a single send, it would be possible for this to release
            // more than one "lock", making it an invalid semaphore
            // implementation
            <-limit
        }(w)
    }
    select{}
}
© www.soinside.com 2019 - 2024. All rights reserved.