仅向通道发送值时进入工作流程

Go workflow when only sending values to channel

我正在按照此 tutorial 学习 Go 中的频道。 当我只向通道发送值时,它会出错。这是示例代码。

package main

import "fmt"

func main() {
  ch := make(chan int)
  ch <- 1

  fmt.Println("Does not work")
}

在这里我只是向通道发送值但没有收到任何东西。它给出一个错误

fatal error: all goroutines are asleep - deadlock! 

但是当我运行遵循代码时它没有给出任何错误

package main

import "fmt"

func sum(s []int, c chan int) {
    sum := 0
    for _, v := range s {
        sum += v
    }
    c <- sum // send sum to c
}

func main() {
    s := []int{7, 2, 8, -9, 4, 0}

    c := make(chan int)
    go sum(s[:len(s)/2], c)
    go sum(s[len(s)/2:], c)

    fmt.Println("did not receive but still works")
}

并打印

did not receive but still works

我不明白为什么它在第二种情况下有效,而在第一种情况下却不起作用。即使在这两种情况下我都没有收到任何关于频道的价值。还有是什么导致了第一种情况下的死锁以及如何在第二种情况下避免死锁?

这两个例子都不起作用。事实上, 发送到通道的任何示例都不会起作用,在任何传统意义上的 "work"。

但为了清楚起见,这里对每个步骤都进行了说明:

第一个例子

ch := make(chan int)

这将创建一个无缓冲通道。无缓冲通道不保存任何数据,它们仅充当通信管道——所有发送的数据必须在程序执行继续之前由其他东西接收——在通道的任一侧。

ch <- 1

此处您在通道上发送数据,但没有任何东西等待接收,因此程序等待。在这种情况下,它会永远等待,因为您从未为该通道创建接收器,因此您的死锁。

第二个例子

c := make(chan int)

再次创建一个无缓冲通道。

go sum(s[:len(s)/2], c)

调用 sum 函数,顺便说一句,由于上述原因,该函数也将永远阻塞——通道上没有接收任何东西,因此它将永远等待。但是,在这种情况下,您已经在 goroutine 中调用了它。 goroutine 将 运行 在一个单独的执行线程中,而程序的其他位 运行。虽然,由于从不从通道接收数据,这个 goroutine 永远不会退出,直到主程序退出。

go sum(s[len(s)/2:], c)

再次,您在 goroutine 中调用 sum。所以在这一点上,你有三个 gorotuine:一个 运行ning main(),每个 运行ning 一个 sum() 的调用。后两者永远不会退出。

然后你的程序退出。当程序退出时,所有 goroutines(包括永远卡在你的频道上的两个)退出。

由于该程序立即退出,因此从未报告过死锁,但确实存在,与您的第一个示例相同。