什么情况下使用 ErrGroup VS waitGroup?

Goroutine 是编写 Go 语言并发程序的强大工具。然而管理协程,特别是在处理协程的错误时,可能会变得繁琐。这时,x/sync 包中的 errgroup 就派上用场了。它提供了一种简化的方法来处理并发任务及其错误。

Example for ErrGroup

下面是一个使用 errorGroup 的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package main

import (
"context"
"errors"
"fmt"
"time"

"golang.org/x/sync/errgroup"
)

func task1(ctx context.Context) error {
fmt.Println("Task 1 started successfully")
select {
case <-time.After(1 * time.Second):
fmt.Println("Task 1 completed successfully")
return nil
case <-ctx.Done():
fmt.Println("Task 1 canceled")
return ctx.Err()
}
}

func task2(ctx context.Context) error {
fmt.Println("Task 2 started successfully")
select {
case <-time.After(2 * time.Second):
fmt.Println("Task 2 processed failed")
return errors.New("Task 2 processed failed due to error")
case <-ctx.Done():
fmt.Println("Task 2 canceled")
return ctx.Err()
}
}

func task3(ctx context.Context) error {
fmt.Println("Task 3 started successfully")
select {
case <-time.After(3 * time.Second):
fmt.Println("Task 3 completed successfully")
return nil
case <-ctx.Done():
fmt.Println("Task 3 canceled")
return ctx.Err()
}
}

func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // Ensure cancellation happens when main() exits

g, ctx := errgroup.WithContext(ctx)

g.Go(func() error {
return task1(ctx)
})

g.Go(func() error {
return task2(ctx)
})

g.Go(func() error {
return task3(ctx)
})

if err := g.Wait(); err != nil {
fmt.Println("Encountered error:", err)
cancel()
} else {
fmt.Println("All tasks completed successfully")
}
}

上面程序的输出是:

1
2
3
4
5
6
Task 1 started successfully
Task 2 started successfully
Task 3 started successfully
Task 1 completed successfully
Task 2 processed failed
Encountered error: Task 2 processed failed due to error

在这个例子中:

  • 我们创建了一个带有可取消上下文的 errgroup
  • 定义了3个任务,task1 和 task3 在一定时间后模拟成功完成,而 task2 在更长的时间后通过返回错误来模拟失败。
  • 使用 g.Go 在单独的 goroutine 中启动每个任务。
  • 调用 g.Wait 等待所有任务完成。如果任何任务遇到错误,g.Wait() 会立即返回该错误。
    在主执行之后,task1 成功完成,task2 遇到了处理失败,而 task3 由于 task2 中的上述失败而被取消。

ErrGroup vs WaitGroup

ErrGroup:

  • 使用 ErrGroup 来管理并发任务中的错误。它聚合了所有协程中的错误,并返回遇到的第一个错误。
  • 需要管理多个可能产生错误的并发任务。
  • 想要利用上下文取消功能来优雅地关闭程序。
  • 不想手动检查多个 WaitGroup 调用的错误
  • 它与 Go 的上下文包无缝集成。任何来自协程的错误都会取消上下文,自动停止其他正在运行的任务。

WaitGroup

  • 使用 WaitGroup 进行基本同步。它简单地等待指定数量的 goroutine 完成后再继续。
  • ]当你只关心任务完成而不预期错误时,它是理想的选择。
  • 它不直接处理错误。你需要在每个 goroutine 中检查错误并单独处理它们。

总结

  • 使用 WaitGroup 进行简单的同步
  • 使用 ErrGroup 进行错误管理,并希望在优雅关闭时有上下文感知的取消。
  • 也可以同时使用它们,WaitGroup 用于基本同步,ErrGroup 用于一组任务中的详细错误处理。

相关的 issue


-------------The End-------------

本文标题:什么情况下使用 ErrGroup VS waitGroup?

文章作者:cloud sjhan

发布时间:2024年05月11日 - 20:05

最后更新:2024年05月11日 - 20:05

原始链接:https://cloudsjhan.github.io/2024/05/11/什么情况下使用-ErrGroup-VS-waitGroup?/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

cloud sjhan wechat
subscribe to my blog by scanning my public wechat account
坚持原创技术分享,您的支持将鼓励我继续创作!
0%
;