Go语言sync.WaitGroup详解及常见误区
本文深入探讨Go语言sync.WaitGroup的计数机制,并分析一个常见的错误用法。我们将通过代码示例演示sync.WaitGroup在并发编程中的应用,以及如何避免Wait方法提前结束的问题。
在一些示例代码中,WaitGroup函数启动多个协程,每个协程调用一个内部函数(例如wgCore)。 该内部函数使用wg.Add(1)增加计数器,并在函数结束时使用defer wg.Done()递减计数器。然而,由于wg.Add(1)位于每个协程内部,WaitGroup的Wait方法无法感知每个协程何时调用Add方法。 这会导致wg.Wait()可能在所有协程调用Add方法之前就开始等待,从而导致程序过早结束,结果与预期不符。
正确的做法是:在启动所有协程之前,使用wg.Add(n) (其中n是协程数量) 预先设置WaitGroup的计数器。这样,WaitGroup的计数器就准确地反映了需要等待的协程数量。每个协程在结束时调用wg.Done()递减计数器。只有当计数器减至0时,wg.Wait()才会结束等待,确保所有协程都已完成执行。
因此,关键在于:sync.WaitGroup的计数器必须在所有协程启动之前被正确初始化。 如果在协程内部增加计数器,WaitGroup无法准确跟踪正在运行的协程数量,导致Wait方法无法正常工作。只有预先设置好WaitGroup的计数器,才能保证Wait方法准确等待所有协程完成。