Waitgroup alternative library

I am considering writting alternative library to sync.Waitgroup.
What I miss/dont like:

  1. method for getting length of waitgroup
  2. when using waitgroup.Done() when the waitgroup counter is zero I get an error.
  3. when using waitgroup.Done() and waitgroup.Add() and waitgroup is nil I get nil error.

Sometimes I need to use functions/goroutines with or without waitgroup.

exmp:
type MyStruct sruct{
wg *sync.Waitgroup
}

func (m *MyStruct) DoSomething(){
wg.Add()
defer wg.Done()
.
.
}

Any suggestions or similar pacakge?

The first point may have some value. But I fail to see why 2. and 3. should be changed.

The documentation for WaitGroups says:

A WaitGroup waits for a collection of goroutines to finish. The main goroutine calls Add to set the number of goroutines to wait for. Then each of the goroutines runs and calls Done when finished. At the same time, Wait can be used to block until all goroutines have finished.

Is that what you’re using it for, or are you solving a different problem and therefore require a different solution?

What do you want this information for? Immediately after getting the length, another goroutine could have called Done and then the length value you have is useless.

That sounds to me like you have a bug in your code. The way you use a wait group is to initialize it with the number of goroutines you’re going to run and then when each of those goroutines is finished, call Done. The situation you describe tells me that you’re “telling” the WaitGroup to wait for, e.g., 5 goroutines and then 6+ goroutines call Done.

I think it’s safe to say that most methods on most types panic when called on nil pointers. What’s wrong with:

func (m *MyStruct) DoSomething() {
    if m.wg != nil {
        m.wg.Add(1)
        defer m.wg.Done()
    }
    // ...
}

That being said, the way the wait group is being used in DoSomething is wrong. You do not defer the call to Done in the same goroutine that called Add. You have to defer calling Done in the goroutine that you’re presumably starting later in DoSomething:

func (m *MyStruct) DoSomething() {
    if m.wg != nil {
        m.wg.Add(1)
    }
    // ...
    go func() {
        defer m.wg.Done()
        // ...
    }()
    // ...
}
1 Like

Yes, this works but I will have this code in every function. In main code do not need to use waitgroup only in tests.
This will not wait because the program ends before the goroutins are initialized: https://play.golang.org/p/N4TttYk8Ofp
This will run as intended: https://play.golang.org/p/fy3wB9tkUw9

I am just not happy with manual management of wg.Add a wg.Done. wg.Add must be added before starting the goroutine otherwise execution will fall through code and halts because the go routine will not manage to run wg.Add(1) before wg.Wait() is reached.

I think you need to refactor your code. Take a look at this: https://play.golang.org/p/0HcRPYIiWF7. Now your MyStruct doesn’t have to know or care if there is or is not a WaitGroup. The WaitGroup is used only in the one function where it’s needed to control synchronization.