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

为什么这里有通道的可变输出

为什么这里有通道的可变输出

Go
慕莱坞森 2023-07-10 15:04:42
我创建 5 个通道并发送数据 5 次:package mainimport "fmt"func greet(c chan string) {    fmt.Println("Hello " + <-c + "!")}func main() {    fmt.Println("main() started")    c := make(chan string)    for i:=0; i<5; i++ {        go greet(c)    }    c <- "AAA"    c <- "BBB"    c <- "CCC"    c <- "DDD"    c <- "EEE"    fmt.Println("main() stopped")}我预计所有 5 个字符串都会被打印出来。但是,我发现输出可变。一些输出是:$ ./rnchannelmain() startedHello AAA!Hello DDD!Hello BBB!Hello CCC!Hello EEE!main() stopped$ ./rnchannelmain() startedHello CCC!Hello DDD!main() stopped$ ./rnchannelmain() startedHello CCC!Hello BBB!Hello AAA!Hello DDD!main() stopped为什么打印的行数可变?
查看完整描述

2 回答

?
繁花如伊

TA贡献2012条经验 获得超12个赞

您不必等到打印完所有字符串才退出。一旦主线程到达执行结束,它就会关闭所有 goroutine 并结束程序。由于这种情况同时发生,因此无法确定将允许打印多少个字符串。



查看完整回答
反对 回复 2023-07-10
?
慕容3067478

TA贡献1773条经验 获得超3个赞

当main()退出时,所有 goroutine 都会被杀死。无法保证您的其他 goroutine 会在此之前完成,这就是并发的本质。以下是修复方法。


首先,让我们对 进行一些更改greet。让其休眠一会儿,以使问题更加明显。我们还将让它接受字符串而不是通道,稍后我们就会明白原因。


func greet(str string) {

    time.Sleep(100 * time.Millisecond)

    fmt.Println("Hello " + str + "!")

}

我们不需要创建一堆 goroutine 从通道读取固定次数,而是需要一个 goroutine 从通道读取直到耗尽。使用 可以最简单地完成此操作range。这充分利用了渠道的优势。

我们还需要一种方法来告诉主程序等待循环完成。使用第二个通道最容易做到这一点。更复杂的同步使用WaitGroups。

c := make(chan string, 2)

done := make(chan bool, 1)

go func() {

    for str := range(c) {

        greet(str)

    }

    done <- true

}()

goroutine 会一直读取c直到关闭。然后它会发送true到频道done。两者都经过缓冲,以避免由于阻塞等待读取或写入通道而导致死锁。


回到main,我们写入通道,显式关闭它,然后等待从 读取done。


    c <- "AAA"

    c <- "BBB"

    c <- "CCC"

    c <- "DDD"

    c <- "EEE"

    close(c)


    <-done

    fmt.Println("main() stopped")

<-done将阻塞,直到有东西可读。这使得 goroutine 能够完成。


并将它们整合在一起。


package main

import(

    "fmt"

    "time"

)

func greet(str string) {

    time.Sleep(100 * time.Millisecond)

    fmt.Println("Hello " + str + "!")

}

func main() {

    fmt.Println("main() started")

    c := make(chan string, 2)

    done := make(chan bool, 1)

    go func() {

        for str := range(c) {

            greet(str)

        }

        done <- true

    }()

    c <- "AAA"

    c <- "BBB"

    c <- "CCC"

    c <- "DDD"

    c <- "EEE"

    close(c)


    <-done

    fmt.Println("main() stopped")

}


查看完整回答
反对 回复 2023-07-10
  • 2 回答
  • 0 关注
  • 79 浏览
慕课专栏
更多

添加回答

举报

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