首页 > 解决方案 > 为什么延迟函数不执行?

问题描述

我正在努力理解 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

据我了解, defer 函数将在其周边函数完成后执行。我无法解释它。

如果我使用 for 循环从通道接收值,它的工作方式如下。

for i := 0; i < 5; i++ {
    fmt.Println(<-myIntChannel) //receiving value
}

谁能帮我理解这个概念?

标签: for-loopgoconcurrencychanneldeferred

解决方案


for ... range只有在从通道接收到所有值并且通道已关闭时,通道才会终止。

在您的示例中,您希望在延迟函数中关闭通道,但这只会在main()返回时运行。但main()只有在循环结束时才会返回。这就是死锁的原因。for循环等待通道关闭,关闭通道等待 for 循环结束。

当您使用循环从通道中准确接收 5 个值时,它会起作用,因为启动的 goroutines 会在其上发送 5 个值。此循环不会等待通道关闭,因此循环可以结束,main()函数也可以结束。

这就是为什么发送者应该关闭通道(而不是接收者),并且问题立即得到解决:

func sendValues(myIntChannel chan int) {
    for i := 0; i < 5; i++ {
        myIntChannel <- i //sending value
    }
    close(myIntChannel)
}

func main() {
    myIntChannel := make(chan int)
    go sendValues(myIntChannel)

    for value := range myIntChannel {
        fmt.Println(value) //receiving value
    }
}

输出(在Go Playground上试试):

0
1
2
3
4

推荐阅读