为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
MM们 2021-12-07 10:14:35
下面是一个例子: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难道我做错了什么?
查看完整描述

3 回答

?
MMTTMM

TA贡献1869条经验 获得超4个赞

默认情况下,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

    }

}

因为没有接收器,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


查看完整回答
反对 回复 2021-12-07
?
桃花长相依

TA贡献1860条经验 获得超8个赞

您创建一个无缓冲通道c

c := make(chan int)

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

简而言之:声明

c <- num

会阻塞。

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

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


查看完整回答
反对 回复 2021-12-07
?
慕田峪7331174

TA贡献1828条经验 获得超13个赞

你使用无缓冲通道,所以你的 goroutine 挂起c <- num
你应该使用缓冲通道,像这样:c := make(chan int, 1)

试试吧 Go playground


查看完整回答
反对 回复 2021-12-07
  • 3 回答
  • 0 关注
  • 158 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信