We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
在并发编程里,sync.WaitGroup并发原语的使用频率非常高,它经常用于协同等待的场景:goroutine A 在检查点(checkpoint)等待一组执行任务的 worker goroutine 全部完成,如果在执行任务的这些 goroutine 还没全部完成, goroutine A 就会阻塞在检查点,直到所有woker goroutine 都完成后才能继续执行。
sync.WaitGroup
goroutine
如果在woker goroutine的执行过程中遇到错误并想要处理该怎么办?WaitGroup并没有提供传播错误的功能,遇到这种场景我们改怎么办?Go语言在扩展库的提供了ErrorGroup并发原语正好适合在这种场景下使用,它在WaitGroup的基础上还提供了,错误传播以及上下文取消的功能。
WaitGroup
Go
ErrorGroup
Go扩展库通过errorgroup.Group提供ErrorGroup原语的功能,它有三个方法可调用:
errorgroup.Group
func WithContext(ctx context.Context) (*Group, context.Context) func (g *Group) Go(f func() error) func (g *Group) Wait() error
接下来我们让主goroutine使用ErrorGroup代替WaitGroup等待所以子任务的完成,ErrorGroup有一个特点是会返回所以执行任务的goroutine遇到的第一个错误。我们试着执行一下下面的程序,观察一下程序的输出。
package main import ( "fmt" "log" "time" "golang.org/x/sync/errgroup" ) func main() { var eg errgroup.Group for i := 0; i < 100; i++ { i := i eg.Go(func() error { time.Sleep(2 * time.Second) if i > 90 { fmt.Println("Error:", i) return fmt.Errorf("Error occurred: %d", i) } fmt.Println("End:", i) return nil }) } if err := eg.Wait(); err != nil { log.Fatal(err) } }
上面程序,遇到i大于90的都会产生错误结束执行,但是只有第一个执行时产生的错误被ErrorGroup返回,程序的输出大概如下:
...... End: 49 End: 26 Error: 98 End: 63 End: 39 End: 50 End: 38 Error: 95 End: 67 End: 65 End: 57 End: 64 2020/12/17 18:11:40 Error occurred: 98
最早执行遇到错误的goroutine输出了Error: 98但是所有未执行完的其他任务并没有停止执行,那么想让程序遇到错误就终止其他子任务该怎么办呢?我们可以用errgroup.Group提供的WithContext方法创建一个带可取消上下文功能的ErrorGroup。
Error: 98
errgroup.Group
WithContext
package main import ( "context" "fmt" "log" "time" "golang.org/x/sync/errgroup" ) func main() { eg, ctx := errgroup.WithContext(context.Background()) for i := 0; i < 100; i++ { i := i eg.Go(func() error { time.Sleep(2 * time.Second) select { case <-ctx.Done(): fmt.Println("Canceled:", i) return nil default: if i > 90 { fmt.Println("Error:", i) return fmt.Errorf("Error: %d", i) } fmt.Println("End:", i) return nil } }) } if err := eg.Wait(); err != nil { log.Fatal(err) } }
Go方法单独开启的gouroutine在执行参数传递进来的函数时,如果函数返回了错误,会对ErrorGroup持有的err字段进行赋值并及时调用cancel函数,通过上下文通知其他子任务取消执行任务。所以上面更新后的程序会员如下类似的输出。
gouroutine
err
cancel
...... Error: 99 Canceled: 68 Canceled: 85 End: 57 End: 51 Canceled: 66 Canceled: 93 Canceled: 72 Canceled: 78 End: 55 Canceled: 74 2020/12/17 18:23:12 Error: 99
使用errorgroup.Group时注意它的两个特点:
Context
The text was updated successfully, but these errors were encountered:
No branches or pull requests
在并发编程里,
sync.WaitGroup
并发原语的使用频率非常高,它经常用于协同等待的场景:goroutine
A 在检查点(checkpoint)等待一组执行任务的 workergoroutine
全部完成,如果在执行任务的这些goroutine
还没全部完成,goroutine
A 就会阻塞在检查点,直到所有wokergoroutine
都完成后才能继续执行。如果在woker
goroutine
的执行过程中遇到错误并想要处理该怎么办?WaitGroup
并没有提供传播错误的功能,遇到这种场景我们改怎么办?Go
语言在扩展库的提供了ErrorGroup
并发原语正好适合在这种场景下使用,它在WaitGroup
的基础上还提供了,错误传播以及上下文取消的功能。Go
扩展库通过errorgroup.Group
提供ErrorGroup
原语的功能,它有三个方法可调用:接下来我们让主
goroutine
使用ErrorGroup
代替WaitGroup
等待所以子任务的完成,ErrorGroup
有一个特点是会返回所以执行任务的goroutine
遇到的第一个错误。我们试着执行一下下面的程序,观察一下程序的输出。上面程序,遇到i大于90的都会产生错误结束执行,但是只有第一个执行时产生的错误被
ErrorGroup
返回,程序的输出大概如下:最早执行遇到错误的
goroutine
输出了Error: 98
但是所有未执行完的其他任务并没有停止执行,那么想让程序遇到错误就终止其他子任务该怎么办呢?我们可以用errgroup.Group
提供的WithContext
方法创建一个带可取消上下文功能的ErrorGroup
。Go
方法单独开启的gouroutine
在执行参数传递进来的函数时,如果函数返回了错误,会对ErrorGroup
持有的err
字段进行赋值并及时调用cancel
函数,通过上下文通知其他子任务取消执行任务。所以上面更新后的程序会员如下类似的输出。使用
errorgroup.Group
时注意它的两个特点:errgroup.Group
在出现错误或者等待结束后都会调用Context
对象 的cancel
方法同步取消信号。The text was updated successfully, but these errors were encountered: