【问题标题】:Go workflow when only sending values to channel仅将值发送到通道时的工作流程
【发布时间】:2019-10-08 12:44:08
【问题描述】:

我正在通过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

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

【问题讨论】:

  • 这个博客解释了你的问题link
  • 第二种情况不起作用。它只是在可能出现死锁之前退出。为什么你会想要只发送到一个频道?
  • 该链接解释了第一部分。但是按照这种逻辑,那么在第二种情况下也应该被卡住让某人读取值
  • 每个 goroutine 阻塞。但是您的程序在报告之前就退出了。

标签: go channel


【解决方案1】:

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

但为了清楚起见,这里有一个步骤:

第一个例子

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)

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

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

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

【讨论】:

  • 当 1 个线程在继续时它仍然是死锁吗?就像我说的那样,有 2 个 goroutine 被泄露了,但它不是一个死机,因为主线程一直没有问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-29
  • 2020-08-27
  • 2019-10-27
  • 1970-01-01
  • 2015-08-17
  • 2016-02-09
  • 2015-01-12
相关资源
最近更新 更多