I'm trying to spin off a set of goroutines, and then wait for them all to finish.
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)
}
wg.Wait()
}
However when I run this code I get the following error:
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
I'm confused because I wrote it pretty much exactly as the documentation example demonstrates.
You need to pass a pointer to the WaitGroup, and not the WaitGroup object. When you pass the actual WaitGroup, Go makes a copy of the value, and calls Done()
on the copy. The result is the original WaitGroup will have ten Add's and no Done's, and each copy of the WaitGroup will have one Done() and however many Add's were there when the WaitGroup was passed to the function.
Pass a pointer instead, and every function will reference the same 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)
}
}
As @Kevin mentioned, you will need to pass a reference to your WaitGroup
. This is actually the one thing I do not like about WaitGroup
because you would be mixing your concurrency logic with your business logic.
So I came up with this generic function to solve this problem for me:
// 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)
}
}
Here is an example:
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
If you would like to use it, you can find it here https://github.com/shomali11/util
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With