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

为什么这个 golang 函数 _not_ 永远运行?

为什么这个 golang 函数 _not_ 永远运行?

Go
叮当猫咪 2021-08-16 15:40:36
我想尝试 FizzBuzz 测试(为什么程序员不能编程),并使用了 Go。它基本上是从 1 到 100 循环,当循环计数器可被 3 整除时打印“Fizz”,被 5 整除时打印“Buzz”,被两者整除时打印“FizzBuzz”,否则只打印数字。在以迭代和递归方式完成之后,我想同时(或通过使用通道)进行。我想出了以下代码,这让我感到惊讶:func fizzbuzzconc() {    // Channels for communication    fizzchan := make(chan int)    buzzchan := make(chan int)    fizzbuzzchan := make(chan int)    nonechan := make(chan int)    // Start go routine to calculate fizzbuzz challenge    go func() {        for i := 1; i <= 100; i++ {            if i % 3 == 0 && i % 5 == 0 {                fizzbuzzchan <- i            } else if i % 3 == 0 {                fizzchan <- i            } else if i % 5 == 0 {                buzzchan <- i            } else {                nonechan <- i            }        }    }()    // When or how does this for loop end?    for {        select {        case i := <-fizzchan:            fmt.Println(i, "Fizz")        case i := <-buzzchan:            fmt.Println(i, "Buzz")        case i := <-fizzbuzzchan:            fmt.Println(i, "FizzBuzz")        case i  := <-nonechan:            fmt.Println(i, i)        }    }}我无法理解 for 循环如何以及为什么停止。没有中断条件或返回语句。为什么它最终完成运行?
查看完整描述

3 回答

?
慕桂英3389331

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

它真的不太好用。

一段时间后,由于剩余的 go-routine 等待没有 goroutine 推送的通道,会发生损耗。所以你所拥有的是一个死锁(这是一个结束程序的致命错误),而不是一个干净的结束。

总之,它“有效”是因为 go 引擎足够聪明,可以检测到死锁。


查看完整回答
反对 回复 2021-08-16
?
慕沐林林

TA贡献2016条经验 获得超9个赞

一种整齐退出的方法是使用退出通道,我们通过关闭它来发出信号。(通过关闭通道发出信号很有用,因为一次可以有多个 goroutine 监听它)。

不过,还有其他方法可以做到这一点 - 如果您只有一个输出通道,那么您可以range在它上面读取结果,close并在完成时读取它。你可以很容易地重新编写它以这样工作。

您可以使用 async.Waitgroup来确保 go 例程也已完成。

func main() {

    // Channels for communication

    fizzchan := make(chan int)

    buzzchan := make(chan int)

    fizzbuzzchan := make(chan int)

    nonechan := make(chan int)

    quit := make(chan struct{})


    // Start go routine to calculate fizzbuzz challenge

    go func() {

        for i := 1; i <= 100; i++ {

            if i%3 == 0 && i%5 == 0 {

                fizzbuzzchan <- i

            } else if i%3 == 0 {

                fizzchan <- i

            } else if i%5 == 0 {

                buzzchan <- i

            } else {

                nonechan <- i

            }

        }

        close(quit)

    }()


    // When or how does this for loop end?

OUTER:

    for {

        select {

        case i := <-fizzchan:

            fmt.Println(i, "Fizz")

        case i := <-buzzchan:

            fmt.Println(i, "Buzz")

        case i := <-fizzbuzzchan:

            fmt.Println(i, "FizzBuzz")

        case i := <-nonechan:

            fmt.Println(i, i)

        case <-quit:

            break OUTER

        }

    }

    fmt.Println("All done")

}


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

添加回答

举报

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