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

为什么所有的 goroutine 都睡着了——死锁。识别瓶颈

为什么所有的 goroutine 都睡着了——死锁。识别瓶颈

Go
四季花海 2021-09-13 20:12:59
package mainimport (    "fmt"    "runtime"    "sync"    "time")func main() {    intInputChan := make(chan int, 50)    var wg sync.WaitGroup    for i := 0; i < 3; i++ {        wg.Add(1)        go worker(intInputChan, wg)    }    for i := 1; i < 51; i++ {        fmt.Printf("Inputs. %d \n", i)        intInputChan <- i    }    close(intInputChan)    wg.Wait()    fmt.Println("Existing Main App... ")    panic("---------------")}func worker(input chan int, wg sync.WaitGroup) {    defer func() {        fmt.Println("Executing defer..")        wg.Done()    }()    for {        select {        case intVal, ok := <-input:            time.Sleep(100 * time.Millisecond)            if !ok {                input = nil                return            }            fmt.Printf("%d  %v\n", intVal, ok)        default:            runtime.Gosched()        }    }}抛出的错误是。致命错误:所有 goroutine 都处于睡眠状态 - 死锁!goroutine 1 [semacquire]:sync.(*WaitGroup).Wait(0xc082004600) c:/go/src/sync/waitgroup.go:132 +0x170 main.main() E:/Go/go_projects/go/src/Test .go:22 +0x21a
查看完整描述

2 回答

?
元芳怎么了

TA贡献1798条经验 获得超7个赞

我刚刚尝试过(操场)通过 awg *sync.WaitGroup并且它有效。


传递sync.WaitGroup意味着传递sync.WaitGroup(按值传递)的副本:goroutine 提到Done()了不同的 sync.WaitGroup.


var wg sync.WaitGroup

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

    wg.Add(1)

    go worker(intInputChan, &wg)

}

请注意&wg:您正在按值传递指向原始 的指针sync.WaitGroup,供 goroutine 使用。


查看完整回答
反对 回复 2021-09-13
?
倚天杖

TA贡献1828条经验 获得超3个赞

如所提到的,不从同步绕包传值的类型,右靠近的顶部sync包文档:“含有在此包中定义的类型的值不应该被复制。 ”这也包括类型本身(sync.Mutexsync.WaitGroup等)。

但是,有几个注意事项:

  • wg.Add如果您知道要添加多少个,您可以只使用一次调用(但如文档所示,请确保任何调用之前都已完成Wait)。

  • 你不想那样打电话runtime.Gosched;它使工人忙循环。

  • 您可以使用range从通道读取以简化在关闭时停止的过程。

  • 对于小函数,您可以使用闭包,而根本不需要传递通道或等待组。

这变成了这样:

package main


import (

    "fmt"

    "sync"

    "time"

)


func main() {

    const numWorkers = 3


    c := make(chan int, 10)

    var wg sync.WaitGroup


    wg.Add(numWorkers)

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

        go func() {

            defer func() {

                fmt.Println("Executing defer…")

                wg.Done()

            }()


            for v := range c {

                fmt.Println("recv:", v)

                time.Sleep(100 * time.Millisecond)

            }

        }()

    }


    for i := 1; i < 51; i++ {

        fmt.Println("send:", i)

        c <- i

    }

    fmt.Println("closing…")

    close(c)


    fmt.Println("waiting…")

    wg.Wait()

    fmt.Println("Exiting Main App... ")

}


查看完整回答
反对 回复 2021-09-13
  • 2 回答
  • 0 关注
  • 222 浏览
慕课专栏
更多

添加回答

举报

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