为什么所有的goroutine都睡着了 - 僵局。识别瓶颈

时间:2015-02-24 08:23:53

标签: go channel

package main

import (
    "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]: 同步。(* WaitGroup).Wait(0xc082004600)     c:/go/src/sync/waitgroup.go:132 + 0x170 main.main()     E:/Go/go_projects/go/src/Test.go:22 + 0x21a

2 个答案:

答案 0 :(得分:8)

我刚试过它(playground)传递wg *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使用。

答案 1 :(得分:3)

如上所述,请不要在sync package documentation的顶部附近按值传递同步包中的类型:“不应复制包含此程序包中定义的类型的值。“这也包括类型本身(sync.Mutexsync.WaitGroup等。”

然而,有几点说明:

  • 如果您知道要添加多少内容,就可以只使用wg.Add一次调用(但是如果有文档记录,请确保 之前可以调用{{1} })。
  • 你不想那样打电话给Wait;它使工人忙碌。
  • 您可以使用runtime.Gosched从频道中读取,以便在关闭时简化停止。
  • 对于小功能,你可以使用一个闭包而不用费心去传递频道或等待组。

将其转化为:

range

playground