得到"致命错误:所有goroutines都睡着了 - 僵局!"使用sync.WaitGroup时

时间:2014-08-11 01:59:22

标签: go

我试图剥离一组goroutines,然后等待它们全部完成。

import "sync"

func doWork(wg sync.WaitGroup) error {
    defer wg.Done()
    // Do some heavy lifting... request URL's or similar
    return nil
}

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go doWork(wg)
    }
}

但是,当我运行此代码时,我收到以下错误:

fatal error: all goroutines are asleep - deadlock!

goroutine 16 [semacquire]:
sync.runtime_Semacquire(0xc20818c658)
    /usr/local/Cellar/go/1.3/libexec/src/pkg/runtime/sema.goc:199 +0x30
sync.(*WaitGroup).Wait(0xc2080544e0)
    /usr/local/Cellar/go/1.3/libexec/src/pkg/sync/waitgroup.go:129 +0x14b
main.main()
    /Users/kevin/code/vrusability/scripts/oculus_share_ratings.go:150 +0x398

我很困惑,因为我写了很多exactly as the documentation example demonstrates

2 个答案:

答案 0 :(得分:9)

您需要将指针传递给WaitGroup,而不是WaitGroup对象。当您传递实际的WaitGroup时,Go会复制该值,并在副本上调用Done()。结果是原始WaitGroup将有十个Add并且没有Done,并且WaitGroup的每个副本将有一个Done(),并且当WaitGroup传递给函数时,有许多Add。在那里。

改为传递指针,每个函数都将引用相同的WaitGroup。

import "sync"

func doWork(wg *sync.WaitGroup) error {
    defer wg.Done()
    // Do some heavy lifting... request URL's or similar
    return nil
}

func main() {
    wg := &sync.WaitGroup{}
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go doWork(wg)
    }
}

答案 1 :(得分:0)

正如@Kevin所提到的,您需要传递对WaitGroup的引用。这实际上是我不喜欢WaitGroup的一件事,因为你会将并发逻辑与业务逻辑混合在一起。

所以我想出了这个通用函数来解决这个问题:

// Parallelize parallelizes the function calls
func Parallelize(functions ...func()) {
    var waitGroup sync.WaitGroup
    waitGroup.Add(len(functions))

    defer waitGroup.Wait()

    for _, function := range functions {
        go func(copy func()) {
            defer waitGroup.Done()
            copy()
        }(function)
    }
}

以下是一个例子:

func1 := func() {
        for char := 'a'; char < 'a' + 3; char++ {
            fmt.Printf("%c ", char)
        }
}

func2 := func() {
        for number := 1; number < 4; number++ {
            fmt.Printf("%d ", number)
        }
}

Parallelize(func1, func2)  // a 1 b 2 c 3

如果您想使用它,可以在https://github.com/shomali11/util

找到它