Go语言sync.WaitGroup与errgroup.Group用法详解
errgroup.Group
和 sync.WaitGroup
的主要区别在于它们的错误处理和协程管理方式。
errgroup.Group
专为并发操作中的错误捕获设计,任意goroutine返回错误时,会立即终止其他goroutine的执行。
而 sync.WaitGroup
主要用于等待多个 goroutine 完成,不会直接处理错误。
用法示例:
// errgroup
import (
"fmt"
"golang.org/x/sync/errgroup"
)
func main() {
group := new(errgroup.Group)
group.Go(func() error {
// 模拟一个操作,可能会失败
err := someOperation()
if err != nil {
return fmt.Errorf("operation failed: %v", err)
}
return nil
})
// 等待所有任务完成,并捕获错误
if err := group.Wait(); err != nil {
fmt.Println("任务执行中遇到错误:", err)
} else {
fmt.Println("所有任务执行完成")
}
}
工作流程
- 调用
group.Go
添加需要并发执行的任务。 group.Wait()
会等待所有任务完成。如果某个 goroutine 返回错误,Wait
会返回该错误。errgroup
会终止错误出现后所有未完成的 goroutine,确保资源节省和异常处理的统一性。
优点
- 错误处理:直接返回错误,避免了手动捕获。
- 中止机制:在遇到错误后自动中止其他任务。
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
var mu sync.Mutex // 用于防止并发访问
results := make(map[int]string)
for i := 1; i <= 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
result, err := someOperation(id)
mu.Lock()
defer mu.Unlock() // 锁定操作以确保安全访问
if err != nil {
results[id] = fmt.Sprintf("error: %v", err)
} else {
results[id] = fmt.Sprintf("success: %v", result)
}
}(i)
}
wg.Wait()
fmt.Println("所有操作完成", results)
}
errgroup.Group
与 sync.WaitGroup
的总结对比
特性 | errgroup.Group | sync.WaitGroup |
---|---|---|
错误处理 | 支持,返回第一个错误并中止其他任务 | 不支持,需手动处理 |
中止机制 | 出现错误后可中止其他任务 | 不支持 |
适合场景 | 并发任务中需统一错误处理 | 仅需等待所有任务完成 |
代码简洁性 | 更简洁,内置错误处理 | 需要手动处理错误和并发访问控制 |
底层实现 | 基于 sync.WaitGroup 进一步封装 | 基础并发任务等待工具 |
选择哪种方式取决于需求,若并发任务中需要统一的错误捕获和中止机制,errgroup.Group
是更好的选择;若仅需等待所有任务执行完毕,可使用 sync.WaitGroup
。