为了账号安全,请及时绑定邮箱和手机立即绑定

无法处理 goroutine 死锁

无法处理 goroutine 死锁

Go
慕村9548890 2023-08-14 16:47:03
我正在尝试向某个频道广播一条消息,我只想让它发送 5 条消息。但我总是收到这个错误: 致命错误:所有 goroutine 都在睡觉 - 死锁!我的代码:package mainimport (    "log"    "sync"    broadcast "github.com/dustin/go-broadcast"    "github.com/pwaller/barrier")//Message boradcastedtype Message struct {    y string    x int}var w sync.WaitGroupvar bar barrier.Barrierfunc main() {    b := broadcast.NewBroadcaster(100)    w.Add(1)    go workerOne(b)    d := Message{"message :", 0}    go func() {        for i := 0; i < 5; i++ {            d.x = i            log.Printf("Sending %v", d)            b.Submit(d)        }        <-bar.Barrier()        b.Close()    }()    w.Wait()}func workerOne(b broadcast.Broadcaster) {    ch := make(chan interface{})    b.Register(ch)    for {        v, ok := <-ch        if ok {            log.Printf("workerOne() reading : %v", v)        } else {            log.Printf("i am here")            close(ch)            b.Unregister(ch)            bar.Fall()            w.Done()            return        }    }}输出 :2019/12/26 20:34:11 Sending {message : 0}2019/12/26 20:34:11 Sending {message : 1}2019/12/26 20:34:11 Sending {message : 2}2019/12/26 20:34:11 Sending {message : 3}2019/12/26 20:34:11 Sending {message : 4}2019/12/26 20:34:11 workerOne() reading : {message : 0}2019/12/26 20:34:11 workerOne() reading : {message : 1}2019/12/26 20:34:11 workerOne() reading : {message : 2}2019/12/26 20:34:11 workerOne() reading : {message : 3}2019/12/26 20:34:11 workerOne() reading : {message : 4}fatal error: all goroutines are asleep - deadlock!我尝试了一切,但它不会在workerOne()函数中抛出条件!ok来关闭通道并结束等待,但仍然有相同的错误
查看完整描述

1 回答

?
慕妹3146593

TA贡献1820条经验 获得超9个赞

barrier您正在使用的软件包已被弃用,取而代之的是 Go 包含的context软件包。你应该改用context。(broadcast目前,您使用的软件包也没有真正给您带来任何好处。)

不过,眼前的问题似乎非常明显:运行的(单个)goroutineworkerOne从通道读取,并且只有当通道关闭(因此ok变为false)时,它才会调用bar.Fall()删除屏障。同时,(单个)goroutine 运行匿名发送者函数:

go func() {

    for i := 0; i < 5; i++ {

        d.x = i

        log.Printf("Sending %v", d)

        b.Submit(d)

    }

    <-bar.Barrier()

    b.Close()

}()

通过包的(非常)简单的消息发布/订阅接口提交五个项目broadcast,然后等待屏障下降。唯一能够放下障碍的 Goroutine(把它想象成唯一能在这里拯救你的地鼠workerOne)就是正在运行的 goroutine 。他现在正在频道接收中等待:


    v, ok := <-ch

您在主 Goroutine 中正在通过sync.WaitGroup变量等待:


w.Wait()

运行匿名发送函数的地鼠正在等待:


    <-bar.Barrier()

谁——在不同的 Go 例程中运行或等待的三个地鼠中的哪一个——将向匿名发送者中的地鼠发出信号,应该v, ok := <-ch得到!ok结果?唯一能做到的就是地鼠奔跑workerOne,但他被困住了。


该broadcast软件包永远不会为您关闭您的频道。取消注册频道只是将其从广播公司的输出频道中删除,从而使未注册的频道保持开放状态;完全有效地关闭广播公司只会注销所有频道,再次让它们保持开放状态。因此,如果您希望关闭自己的频道,则必须自己在其他地方执行此操作。


或者,您可以修改您的设置workerOne,使其不依赖于关闭的通道。例如,您的变量d有 anx int和 a y string; 您可以选择其中一个或两个,并确定读取“drop thebarrier”的字符串值(可能int还具有某些特定值)意味着“bar.Fall()立即调用”。如果您这样做,您从这两个非标准包中获得的收益会更少。


查看完整回答
反对 回复 2023-08-14
  • 1 回答
  • 0 关注
  • 125 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信