为什么延迟函数不执行?

我正在努力理解 Go 中的并发性。


package main


import "fmt"


func sendValues(myIntChannel chan int) {

    for i := 0; i < 5; i++ {

        myIntChannel <- i //sending value

    }

}


func main() {

    myIntChannel := make(chan int)

    defer close(myIntChannel)

    go sendValues(myIntChannel)


    for value := range myIntChannel {

        fmt.Println(value) //receiving value

    }

}

上面的代码给出以下输出:


0

1

2

3

4

fatal error: all goroutines are asleep - deadlock!


goroutine 1 [chan receive]:

main.main()

    /Users/spikki/Desktop/GoLearning/go_channel.go:51 +0x10b

根据我的理解,延迟函数将在其周围函数完成后执行。我无法解释它。


如果我使用 for 循环从通道接收值,其工作原理如下。


for i := 0; i < 5; i++ {

    fmt.Println(<-myIntChannel) //receiving value

}

谁能帮助我理解这个概念?


杨魅力
浏览 161回答 2
2回答

BIG阳

for ... range仅当从通道接收到所有值并且通道已关闭时,通道上的操作才会终止。在您的示例中,您希望在延迟函数中关闭通道,但这只会在main()返回时运行。但main()只有在循环结束时才会返回。这就是死锁的原因。循环for等待通道关闭,关闭通道等待for循环结束。当您使用循环从通道接收恰好 5 个值时,它会起作用,因为启动的 Goroutine 会在其上发送 5 个值。该循环不会等待通道关闭,因此循环可以结束,函数也可以结束main()。这就是为什么发送者应该关闭通道(而不是接收者),问题就立即解决:func sendValues(myIntChannel chan int) {&nbsp; &nbsp; for i := 0; i < 5; i++ {&nbsp; &nbsp; &nbsp; &nbsp; myIntChannel <- i //sending value&nbsp; &nbsp; }&nbsp; &nbsp; close(myIntChannel)}func main() {&nbsp; &nbsp; myIntChannel := make(chan int)&nbsp; &nbsp; go sendValues(myIntChannel)&nbsp; &nbsp; for value := range myIntChannel {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(value) //receiving value&nbsp; &nbsp; }}输出(在Go Playground上尝试):01234

一只萌萌小番薯

用稍微不同的术语来解释它,您的代码的作用是:func main() {&nbsp; &nbsp; ...&nbsp; &nbsp; while myIntChannel is not closed {&nbsp; &nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; }&nbsp; &nbsp; close myIntChannel&nbsp;}现在您可以看到僵局从何而来。虽然上面的答案是有效的,但如果您更喜欢使用,您也可以尝试这个defer:func sendValues(myIntChannel chan int) {&nbsp; &nbsp; defer close(myIntChannel)&nbsp; &nbsp; for i := 0; i < 5; i++ {&nbsp; &nbsp; &nbsp; &nbsp; myIntChannel <- i //sending value&nbsp; &nbsp; }}func main() {&nbsp; &nbsp; myIntChannel := make(chan int)&nbsp; &nbsp; go sendValues(myIntChannel)&nbsp; &nbsp; for value := range myIntChannel {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(value) //receiving value&nbsp; &nbsp; }}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go