8

Let’s say I use a WaitGroup to make the main thread of an application wait until all the goroutines I have launched from said main have completed.

Is there a safe, straightforward, way to assess at any point in time how many goroutines associated with said WaitGroup are still running?

blackgreen
  • 34,072
  • 23
  • 111
  • 129
Serge Hulne
  • 594
  • 5
  • 17

2 Answers2

18

The internal state of the WaitGroup is not exposed, and it won't be: https://github.com/golang/go/issues/7202

I don't think we're likely to make this API more complex. I don't see any way to use counter and waiters that is not subject to race conditions, other than simply printing them out. And for that you can maintain your own counts.

You could implement a counter yourself:

type WaitGroupCount struct {
    sync.WaitGroup
    count int64
}

func (wg *WaitGroupCount) Add(delta int) {
    atomic.AddInt64(&wg.count, int64(delta))
    wg.WaitGroup.Add(delta)
}

func (wg *WaitGroupCount) Done() {
    atomic.AddInt64(&wg.count, -1)
    wg.WaitGroup.Done()
}

func (wg *WaitGroupCount) GetCount() int {
    return int(atomic.LoadInt64(&wg.count))
}

// Wait() promoted from the embedded field

However, even if the counter access is synchronized, it will become stale immediately after you read it, since other goroutines may go on and call Add or Done irrespective of what you are doing with the count — unless you synchronize the entire operation that depends on the count. But in that case, you might need a more complex data structure altogether.

blackgreen
  • 34,072
  • 23
  • 111
  • 129
3

Is there a safe, straightforward, way to assess at any point in time how many goroutines associated with said waitgroup are still running?

No, there isn't.

Simply because Go (the language) has no notion of "goroutines associated with [a] waitgroup".

Volker
  • 40,468
  • 7
  • 81
  • 87
  • Alternatively: the number of goroutines “added” to a given waitgroup or being “monitored” using a given waitgroup (using wg.Add(1) and we:Done()) – Serge Hulne Aug 31 '21 at 08:30
  • 1
    @SergeHulne wg.Add(n) doesn't work on goroutines. goroutines have no real identity. wg.Add(n) add n to the internal counter but this need not correspond to a goroutine. Are you not really interested in goroutines but in the current Waitgroup count? – Volker Aug 31 '21 at 08:51
  • All right, how do you build a workaround to access the internal counter (a getter), alternatively how do you mimic said counter: will incrementing / decrementing an integer (inside a mutex) for each Add() / Done() pair do the trick? – Serge Hulne Aug 31 '21 at 09:09
  • 3
    blackgreen's answer is all there is to know. The internals of a WaitGroup are not exposed and you cannot get hold of the. If you want to record what happend to (and thus what state a WaitGroup is in) you have to implement your own. Typically by wrapping a WaitGroup, capturing Adds and Dones and keeping your own counter. – Volker Aug 31 '21 at 10:03