通道接收仅来自 Go 例程中的 Println 会引发死锁异常



我有一些代码,我试图使用 fmt 在 goroutine 中打印频道的内容。Println.下面是代码的简化版本。

package main
import "fmt"
import "time"
func main() {
  ch := make(chan int)
  go fmt.Println(<-ch);
  ch<- 10;
  time.Sleep(time.Second * 10);
}

当我运行上面的代码时,我收到此错误。

fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
        C:/cygwin64/home/vmadhusudana/go/channel.go:9 +0x67
exit status 2

但是,当我调用 fmt 时,它工作正常。Println from a function

package main
import "fmt"
import "time"
func main() {
    ch := make(chan int)
    go func(){fmt.Println(<-ch)}();
    ch<- 10;
    time.Sleep(time.Second * 10);
}

这里有什么不同?

在第一个版本中,通道读取是从主 go-routine 执行的 - 因此存在死锁。第二个版本,读取是从创建的go-routine完成的。

基本上是这样的:

go fmt.Println(<-ch);

成为:

v := <-ch
go fmt.Println(v);

由于函数的参数在调用之前被计算

附言延迟语句的行为类似。因此,如果您希望传递给go-routine或defer语句的值在"运行时"进行评估,请始终使用闭包。

// receive the value from channel firstly
// then create new goroutine to println
go fmt.Println(<-ch)
// receive channel in new goroutine 
go func(){fmt.Println(<-ch)}()

https://play.golang.org/p/xMyqd-Yr8_a

这将帮助您了解执行的顺序。

最新更新