• Dmitry Vyukov's avatar
    sync: simplify WaitGroup · 03a48ebe
    Dmitry Vyukov authored
    A comment in waitgroup.go describes the following scenario
    as the reason to have dynamically created semaphores:
    
    // G1: Add(1)
    // G1: go G2()
    // G1: Wait() // Context switch after Unlock() and before Semacquire().
    // G2: Done() // Release semaphore: sema == 1, waiters == 0. G1 doesn't run yet.
    // G3: Wait() // Finds counter == 0, waiters == 0, doesn't block.
    // G3: Add(1) // Makes counter == 1, waiters == 0.
    // G3: go G4()
    // G3: Wait() // G1 still hasn't run, G3 finds sema == 1, unblocked! Bug.
    
    However, the scenario is incorrect:
    G3: Add(1) happens concurrently with G1: Wait(),
    and so there is no reasonable behavior of the program
    (G1: Wait() may or may not wait for G3: Add(1) which
    can't be the intended behavior).
    
    With this conclusion we can:
    1. Remove dynamic allocation of semaphores.
    2. Remove the mutex entirely and instead pack counter and waiters
       into single uint64.
    
    This makes the logic significantly simpler, both Add and Wait
    do only a single atomic RMW to update the state.
    
    benchmark                            old ns/op     new ns/op     delta
    BenchmarkWaitGroupUncontended        30.6          32.7          +6.86%
    BenchmarkWaitGroupActuallyWait       722           595           -17.59%
    BenchmarkWaitGroupActuallyWait-2     396           319           -19.44%
    BenchmarkWaitGroupActuallyWait-4     224           183           -18.30%
    BenchmarkWaitGroupActuallyWait-8     134           106           -20.90%
    
    benchmark                          old allocs     new allocs     delta
    BenchmarkWaitGroupActuallyWait     2              1              -50.00%
    
    benchmark                          old bytes     new bytes     delta
    BenchmarkWaitGroupActuallyWait     48            16            -66.67%
    
    Change-Id: I28911f3243aa16544e99ac8f1f5af31944c7ea3a
    Reviewed-on: https://go-review.googlesource.com/4117
    Run-TryBot: Dmitry Vyukov <dvyukov@google.com>
    TryBot-Result: Gobot Gobot <gobot@golang.org>
    Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
    Reviewed-by: 's avatarRuss Cox <rsc@golang.org>
    03a48ebe
waitgroup.go 4.15 KB