当前位置: 首页 > 面试题库 >

Go中的频道死锁

常宸
2023-03-14
问题内容

由于以下代码中的某种原因,我收到“致命错误:所有goroutine都在睡眠-死锁!”。我正在使用应该不阻塞的缓冲通道。不知道我在做什么错

package main

import (
    "fmt"
    "sync"
)

func main() {
    c := make(chan int, 2)
    var wg sync.WaitGroup
    wg.Add(2)

    go doSomething(c, wg)
    go doSomething(c, wg)
    go doSomething(c, wg)

    wg.Wait()

    close(c)

    for v := range c {
        fmt.Print(v)
    }

}

func doSomething(c chan<- int, wg sync.WaitGroup) {
    defer wg.Done()
    c <- 1

}

游乐场链接https://play.golang.org/p/J9meD5aKna


问题答案:

虽然您的解决方案可能会起作用,但我对此并不满意。

首先,您需要更改通道大小以使其起作用这一事实表明存在潜在的问题/错误。现在,每次您要启动另一个时doSomething,都必须记住要更改通道的长度。

其次,您要等到所有goroutine完成后才能从通道读取。这是一种“浪费”,因为通道范围循环的要点之一是您不必等到所有项目生成(写入通道)后,就可以立即处理这些项目。他们已经准备好了。

所以我会像这样写你的代码

func main() {
    c := make(chan int)

    var wg sync.WaitGroup
    wg.Add(3)
    go func() {
        doSomething(c)
        defer wg.Done()
    }()
    go func() {
        doSomething(c)
        defer wg.Done()
    }()
    go func() {
        doSomething(c)
        defer wg.Done()
    }()

    go func() {
        wg.Wait()
        defer close(c)
    }()

    for v := range c {
        fmt.Print(v)
    }
}

func doSomething(c chan<- int) {
    c <- 1
}

https://play.golang.org/p/T3dfiztKot

请注意,等待和关闭通道现在是如何在其自己的goroutine中进行的-这允许立即开始在通道上进行迭代(该通道现在没有缓冲!)。

我还更改了代码,以WaitGroup使它永远不会离开声明它的范围(即,它不用作参数),这是我个人的喜好。我相信它使代码更易于遵循和理解。



 类似资料:
  • 问题内容: 这仅适用于至少两个发送到通道的设备。在deviceChan中只有一台设备时,该功能不会接收任何东西。通道在WriteDeviceToFile到达之前消失了吗? 问题答案: 返回时程序退出。写入文件之前没有任何阻止

  • 问题内容: 输出: 问题答案: 之所以陷入僵局,是因为结构是通过值而不是通过引用传递的。 将WaitGroup传递给函数时,需要传递 指针 而不是值。否则,将使用WaitGroup的副本。 这是您的工作示例:

  • 问题内容: 我有三个并发的go例程,如下所示, 该逻辑代码每次都会出现死锁情况。实际上,当它运行时,只需多次执行例程1的打印语句(*标记之间的语句)(尽管我的打印语句只有一个)并给出死锁错误。有人可以告诉我代码逻辑有什么问题吗?谢谢。 注意 有关更多信息,请参见http://play.golang.org/p/pW6aXryUaK,此处仅执行行号290。包含错误的原始代码可以在play.golan

  • 我使用deadLetterChannel来处理异常,并将它们发送到错误队列。 是否可以使用其他邮件标头来丰富邮件?还是我必须为此使用 onException?

  • 问题内容: 当我执行一些go实践代码时,遇到一个问题,通道可以关闭两次,如下所示: 输出: 但是,当我手动关闭通道两次时,我得到了。 为什么上面的代码可以两次关闭? 问题答案: 一个通道只能关闭一次,尝试关闭一个已关闭的通道紧急情况。 但接收从封闭通道没有限制,从关闭信道接收: 封闭通道上的接收操作始终可以立即进行,在接收到任何先前发送的值之后,得出元素类型的零值。 Go应用程序运行直到其主要go

  • HTTP接口文档 频道集成信息接口 GET /activity/api/integrated_info?actid=xxxx URL 参数 参数 描述 取值 是否必填 actid 频道HashID string 必填 返回 参数 描述 取值 errcode 错误码 int msg 错误信息 string name 频道名称 string description 频道描述 string visibl