如何在同一循环内向/从通道发送和接收值?

Rhi*_*rva 0 channel go goroutine

下面是一个例子:

func main() {
    c := make(chan int)
    i := 0

    go goroutine(c)

    c <- i
    time.Sleep(10 * time.Second)

}

func goroutine(c chan int) {
    for {
        num := <- c
        fmt.Println(num)
        num++
        time.Sleep(1 * time.Second)
        c <- num
    }
}
Run Code Online (Sandbox Code Playgroud)

我在 goroutine 中尝试做的是从通道接收数字,打印它,递增并在一秒钟后将其发送回通道。在此之后,我想重复这个动作。

但因此,操作只进行一次。

输出:

0
Run Code Online (Sandbox Code Playgroud)

难道我做错了什么?

End*_*imo 5

默认情况下,goroutine 通信是synchronousand unbuffered: 发送不会完成,直到有接收者接受该值。必须有一个接收者准备好从通道接收数据,然后发送者可以将它直接交给接收者。

所以通道发送/接收操作阻塞,直到另一端准备好:

1.通道上的发送操作会阻塞,直到接收器可用于同一通道:如果没有接收器的值 on 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
    }
}
Run Code Online (Sandbox Code Playgroud)

因为没有接收器,goroutine 挂起并只打印第一个数字。

为了解决这个问题,我们需要定义一个新的 goroutine,它以无限循环的方式从通道中读取数据。

func receive(ch chan int) {
    for {
        fmt.Println(<- ch)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在main()

func main() {
    ch := make(chan int)
    go pump(ch)
    go receive(ch)
}
Run Code Online (Sandbox Code Playgroud)

Go Playground

  • 请注意,您的最后一个 `main()` 函数在启动第二个 goroutine 后返回,因此程序可能会立即退出(它不会等待非 `main` goroutines 完成)。它可能是 `pump()` 和 `receive()` 甚至不会被调用。 (2认同)