解决Golang 中使用WaitGroup的那点坑
Golang中的WaitGroup是协调多个goroutine之间任务的同步工具,它通过Add()方法添加任务数,通过Done()方法减少任务数,而Wait()方法会阻塞直到所有任务都完成。使用WaitGroup的方式简单直观,但在实际使用过程中,还是存在一些小坑需要注意。
1. 进行WaitGroup.Add()操作时,应该在goroutine之外执行。
为了让所有的goroutine都完成操作,我们需要先对WaitGroup进行Add()操作,将需要完成的任务数量加上。但是,由于Add()操作会改变WaitGroup的内部计数器,所以在goroutine中直接调用Add()会造成计数器的竞争条件。
正确的使用方式是在goroutine之外添加任务数量,这样可以避免竞争条件,保证计数器的正确性。例如:
wg.Add(1)
go func() {
defer wg.Done()
// 执行任务
}()
2. 应该在goroutine中调用WaitGroup.Done()操作。
当每个goroutine完成任务后,应该调用WaitGroup的Done()方法,以便告诉WaitGroup一个任务已经完成。这样,WaitGroup内部计数器将减少一个,直到计数器为0时,调用Wait()方法才会返回。
需要注意的是,在因某种原因意外退出的goroutine中,同样需要调用Done()方法,以保证内部计数器的正确性。例如:
wg.Add(1)
go func() {
// 执行任务
if err != nil {
// 意外退出
wg.Done()
return
}
wg.Done()
}()
3. 当Wait()方法返回后,WaitGroup不会自动清空计数器。
WaitGroup提供了一个计数器,但是它不会自动清空。如果需要对同一个WaitGroup再次使用,需要手动重置其内部计数器。正确的写法如下:
wg.Wait()
wg.Add(10) // 重置计数器为10
4. WaitGroup不适合处理复杂的依赖关系。
WaitGroup只能处理简单的任务同步,无法解决复杂的依赖关系。如果任务之间有先后顺序或者需要等待其他任务完成后再进行,应该考虑使用channel、Mutex等其它同步工具来实现。
总体来说,WaitGroup是Golang中一个非常实用的同步工具,尤其适用于较为简单的任务同步,但在使用时还是需要注意一些细节。希望以上内容可以帮助大家更好地掌握WaitGroup的使用技巧,避免被一些小坑所困扰。
