Timeout for WaitGroup.Wait()

前端 未结 7 952
清歌不尽
清歌不尽 2021-02-01 04:33

What is an idiomatic way to assign a timeout to WaitGroup.Wait() ?

The reason I want to do this, is to safeguard my \'scheduler\' from potentially awaiting an errant \'w

7条回答
  •  傲寒
    傲寒 (楼主)
    2021-02-01 05:12

    Mostly your solution you posted below is as good as it can get. Couple of tips to improve it:

    • Alternatively you may close the channel to signal completion instead of sending a value on it, a receive operation on a closed channel can always proceed immediately.
    • And it's better to use defer statement to signal completion, it is executed even if a function terminates abruptly.
    • Also if there is only one "job" to wait for, you can completely omit the WaitGroup and just send a value or close the channel when job is complete (the same channel you use in your select statement).
    • Specifying 1 second duration is as simple as: timeout := time.Second. Specifying 2 seconds for example is: timeout := 2 * time.Second. You don't need the conversion, time.Second is already of type time.Duration, multiplying it with an untyped constant like 2 will also yield a value of type time.Duration.

    I would also create a helper / utility function wrapping this functionality. Note that WaitGroup must be passed as a pointer else the copy will not get "notified" of the WaitGroup.Done() calls. Something like:

    // waitTimeout waits for the waitgroup for the specified max timeout.
    // Returns true if waiting timed out.
    func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool {
        c := make(chan struct{})
        go func() {
            defer close(c)
            wg.Wait()
        }()
        select {
        case <-c:
            return false // completed normally
        case <-time.After(timeout):
            return true // timed out
        }
    }
    

    Using it:

    if waitTimeout(&wg, time.Second) {
        fmt.Println("Timed out waiting for wait group")
    } else {
        fmt.Println("Wait group finished")
    }
    

    Try it on the Go Playground.

提交回复
热议问题