I am testing sync.WaitGroup
, if I put defer wg.Done()
in the begining of the function, like this:
package main
import (
"fmt"
"sync"
"time"
)
func worker(wg *sync.WaitGroup, id int) error {
defer wg.Done() // put here cause error
fmt.Printf("Worker %v: Finished\n", id)
if true {
return nil
}
return nil
}
var wg sync.WaitGroup // I should put `wg` outside of this function
func callWorker(i int){
fmt.Println("Main: Starting worker", i)
fmt.Printf("Worker %v: Finished\n", id)
wg.Add(1)
go worker(&wg, i)
wg.Wait()
}
func main() {
for i := 0; i < 1000; i {
go callWorker(i)
}
time.Sleep(time.Second * 60)
fmt.Println("Main: Waiting for workers to finish")
fmt.Println("Main: Completed")
}
I will get WaitGroup is reused before previous Wait has returned
in some cases, like this
but if I put defer wg.Done()
in the end of function, it runs successfully, why?
func worker(wg *sync.WaitGroup, id int) error {
fmt.Printf("Worker %v: Finished\n", id)
if true {
return nil
}
defer wg.Done() // put here, it is ok
return nil
}
CodePudding user response:
The docs state that "If a WaitGroup is reused to wait for several independent sets of events, new Add calls must happen after all previous Wait calls have returned"
You are calling wg.Done() in some goroutines before calling wg.Add(1) in others, which is not allowed, as stated by the docs. You need to call wg.Add before you start all those goroutines, and you might as well just call it once, wg.Add(1000)
The reason your other code works is because it never calls wg.Done(), you have
if true {
return nil
}
defer wg.Done()
so you always return without reaching the defer statement, so there is never any calls to wg.Done()
Do this:
func callWorker(i int){
fmt.Println("Main: Starting worker", i)
// you cannot call Add here because Done has been called in other goroutines
go worker(&wg, i)
wg.Wait()
}
func main() {
wg.Add(1000) // <---- You must call Add before Done is called in any goroutine
for i := 0; i < 1000; i {
go callWorker(i)
}
time.Sleep(time.Second * 60)
fmt.Println("Main: Completed")
}