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

我想尝试 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 循环如何以及为什么停止。没有中断条件或返回语句。为什么它最终完成运行?


叮当猫咪
浏览 156回答 3
3回答

慕桂英3389331

它真的不太好用。一段时间后,由于剩余的 go-routine 等待没有 goroutine 推送的通道,会发生损耗。所以你所拥有的是一个死锁(这是一个结束程序的致命错误),而不是一个干净的结束。总之,它“有效”是因为 go 引擎足够聪明,可以检测到死锁。

慕沐林林

一种整齐退出的方法是使用退出通道,我们通过关闭它来发出信号。(通过关闭通道发出信号很有用,因为一次可以有多个 goroutine 监听它)。不过,还有其他方法可以做到这一点 - 如果您只有一个输出通道,那么您可以range在它上面读取结果,close并在完成时读取它。你可以很容易地重新编写它以这样工作。您可以使用 async.Waitgroup来确保 go 例程也已完成。func main() {&nbsp; &nbsp; // Channels for communication&nbsp; &nbsp; fizzchan := make(chan int)&nbsp; &nbsp; buzzchan := make(chan int)&nbsp; &nbsp; fizzbuzzchan := make(chan int)&nbsp; &nbsp; nonechan := make(chan int)&nbsp; &nbsp; quit := make(chan struct{})&nbsp; &nbsp; // Start go routine to calculate fizzbuzz challenge&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; for i := 1; i <= 100; i++ {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if i%3 == 0 && i%5 == 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fizzbuzzchan <- i&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if i%3 == 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fizzchan <- i&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else if i%5 == 0 {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; buzzchan <- i&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nonechan <- i&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; close(quit)&nbsp; &nbsp; }()&nbsp; &nbsp; // When or how does this for loop end?OUTER:&nbsp; &nbsp; for {&nbsp; &nbsp; &nbsp; &nbsp; select {&nbsp; &nbsp; &nbsp; &nbsp; case i := <-fizzchan:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i, "Fizz")&nbsp; &nbsp; &nbsp; &nbsp; case i := <-buzzchan:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i, "Buzz")&nbsp; &nbsp; &nbsp; &nbsp; case i := <-fizzbuzzchan:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i, "FizzBuzz")&nbsp; &nbsp; &nbsp; &nbsp; case i := <-nonechan:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(i, i)&nbsp; &nbsp; &nbsp; &nbsp; case <-quit:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; break OUTER&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; fmt.Println("All done")}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go