如何在同一个循环中发送和接收值 to/from 通道?

How to send and receive values to/from the channel within the same loop?

这是一个例子:

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
    }
}

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

但是结果只做了一次操作

输出:

0

我是不是做错了什么?

您使用无缓冲通道,所以您的 goroutine 挂起 c <- num
您应该使用缓冲通道,如下所示:c := make(chan int, 1)

Go playground

上试用

您使用

创建了一个无缓冲通道 c
c := make(chan int)

在无缓冲的通道上,操作是对称的,即通道上的每个发送都只需要一个接收,每个接收只需要一个发送。您将 i 发送到通道中,goroutine 将其接收到 num 中。之后,goroutine 将递增的 num 发送到通道中,但是没有人在那里接收它。

简而言之:声明

c <- num

会阻止。

您可以使用 1 缓冲通道,应该可以。

您的代码还有另一个问题,您在 main 中通过等待十秒钟解决了这个问题:您不知道 goroutine 何时完成。通常,在这些情况下使用 sync.WaitGroup但是:你的协程没有完成。引入一个 chan struct{} 是惯用的,你在一段时间后在你的主 goroutine 中关闭并在 worker goroutine 的两个通道上 select

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

所以通道 send/receive 操作阻塞,直到另一端准备就绪:

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 挂起并只打印第一个数字。

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

func receive(ch chan int) {
    for {
        fmt.Println(<- ch)
    }
}

然后在main():

func main() {
    ch := make(chan int)
    go pump(ch)
    go receive(ch)
}

Go Playground