writing/reading 多值 to/from 无缓冲通道在 Go 中如何工作?

How does writing/reading multiple values to/from a unbuffered channel work in Go?

这似乎挑战了我对无缓冲通道的理解,即它只能取一个值,然后它会阻塞 reader 来读取它。

  1. 下面的代码writeToChan如何写出3个值?
  2. 更令人惊讶的是,这些值是如何在以后读取的,尽管顺序不同?

摘自https://golang.org/doc/effective_go#channels

Receivers always block until there is data to receive. If the channel is unbuffered, the sender blocks until the receiver has received the value. If the channel has a buffer, the sender blocks only until the value has been copied to the buffer; if the buffer is full, this means waiting until some receiver has retrieved a value.

package main

import (
    "fmt"
    "time"
)

func main() {

    ch := make(chan int)

    go writeToChan(ch)
    go rdFrmChan(ch)
    
    x := <- ch
    fmt.Println("main read 1 -:",x)
    fmt.Println("main read 2 -:",<-ch)
}

func writeToChan(c chan int) {
    time.Sleep(time.Second * 1)
    c <- 42
    c <- 27
    c <- 9
}

func rdFrmChan(c chan int) {
    fmt.Println("Go routine read :", <-c)
}

输出:

Go routine read : 27
主读 1 -: 42
主读 2 -: 9


Playground link: https://play.golang.org/p/DYzfYh-kXnC

粘贴的每一行摘录都由您的示例代码证明,如果您了解事件发生的顺序。

  1. goroutines 启动后,您的主例程被阻止从通道 c 读取,因为它还没有看到要读取的值。 writeToChan 例程在将第一个值写入通道之前等待一秒钟

  2. goroutine rdFrmChan 也被阻塞了,因为它在通道 ch

    上等待读取
  3. 1s后,当writeToChan上的sleep到期,第一个write(c <- 42)会先unblock你的main routine,导致value存入x 即 42

  4. 接下来 rdFrmChan 在下一次写入通道 (c <- 27) 时解除阻塞并看到值 27。例程在打印值 [ 后于此时终止=21=]

  5. 此时,只有写入值和读取值。 goroutine 的第三次写入 (c <- 9) 允许主例程读取值作为 <-ch 的一部分并打印它