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

Go 单个通道上有多个接收器。谁得到数据?,go,blocking,channel,Go,Blocking,Channel,无缓冲信道阻塞接收机,直到信道上有数据可用。我不清楚在同一通道上的多个接收器(比如使用goroutines时)这种阻塞是如何工作的。我确信,只要该频道上没有发送数据,它们都会阻塞。 但是,一旦我向该通道发送一个值,会发生什么?哪个接收器/goroutine将获得数据并因此解除阻塞?都是吗?第一排?随机?一个随机(非确定性)的人将收到它 见语言: “select”语句的执行分为几个步骤: 对于语句中的所有情况,receive操作的通道操作数以及send的通道和右侧表达式 语句在输入时按源代码顺序计

无缓冲信道阻塞接收机,直到信道上有数据可用。我不清楚在同一通道上的多个接收器(比如使用goroutines时)这种阻塞是如何工作的。我确信,只要该频道上没有发送数据,它们都会阻塞。
但是,一旦我向该通道发送一个值,会发生什么?哪个接收器/goroutine将获得数据并因此解除阻塞?都是吗?第一排?随机?

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

见语言:

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

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

  • 默认情况下,goroutine通信为
    同步
    无缓冲
    :只有在有接收器接受该值时,发送才会完成。必须有一个接收器准备从通道接收数据,然后发送方可以直接将数据移交给接收器

    因此,通道发送/接收操作将阻塞,直到另一端准备就绪:

    1.频道上的发送操作会一直阻塞,直到同一频道有可用的接收器:如果没有接收器接收
    ch
    上的值,则无法在该频道中输入其他值。另一种方法是:当通道不为空时,
    ch
    中不能发送新值!因此,发送操作将等待
    ch
    再次可用

    2.信道的接收操作会阻塞,直到发送方可用于同一信道:如果信道中没有值,则接收器会阻塞

    以下示例对此进行了说明:

    package main
    import "fmt"
    
    func main() {
        ch1 := make(chan int)
        go pump(ch1) // pump hangs
        fmt.Println(<-ch1) // prints only 0
    }
    
    func pump(ch chan int) {
        for i:= 0; ; i++ {
            ch <- i
        }
    }
    

    如果节目允许多个goroutine在一个频道上接收,则发送方正在广播。每个接收器都应该能够同等地处理数据。因此,go运行时使用何种机制来决定许多goroutine接收器中的哪一个将运行Cf并不重要。但如果通道未缓冲,则每个发送的项目只运行一个

    比赛条件?这样做安全吗?是的,当然,goroutine获得元素只是一种活泼。我不会称之为“比赛条件”。该术语通常定义为表示由于不安全并发访问变量而导致的意外行为。频道被设计成可以同时安全访问,一个无缓冲的频道上有多个阅读器没有问题。我认为你根本不需要这个术语,添加它只是混淆了问题。因为通道的内部结构将接收操作序列化,所以它本身并没有什么“快速性”,用CSP术语来说,这是一个不确定的选择。这与比赛条件不同。正如JimB所说,后者是偶然和有害的。如果您希望选择是确定性的,您可能需要使用N个通道,而不是1个,用于N个接收goroutine。
    func receive(ch chan int) {
        for {
            fmt.Println(<- ch)
        }
    }
    
    func main() {
        ch := make(chan int)
        go pump(ch)
        receive(ch)
    }