semgroup 用于并发执行一组任务,提供限制协程数量、同步等待任务执行完成及错误信息传递的能力。不同于 errgroup ,semgroup 会执行所有任务,且收集任务产生的 error 信息。在全部任务执行完成后,将收集的 error 信息返回给开发者。
使用方法
快速使用请看官网的使用方法,此处不赘述
示例 TestDemo
中用到了如下功能,可以按需使用
context
定义了超时时间,可以限制整个任务的执行时间任务并行执行,且向外丢出了自定义 error
使用
errors.Is
和errors.As
处理 error使用了拓展的
ExportMultiError
函数将所有内部错误全部输出(附带错误中包含了关键信息如taskId
,可以在后续的程序中使用)func TestDemo(t *testing.T) { // 可控制任务整体的执行时间 timedCtx, cancel := context.WithTimeout(context.Background(), time.Hour) defer cancel() g := NewGroup(timedCtx, 1) fe := fooErr{taskId: 1, msg: "__foo__"} g.Go(func() error { return fe }) g.Go(func() error { return os.ErrClosed }) g.Go(func() error { return nil }) err := g.Wait() if err == nil { t.Fatalf("g.Wait() should return an error") } var ( fbe fooErr ) // Is 可用于抛出错误的判断 if !errors.Is(err, fe) { t.Errorf("error should be equal fooErr") } // Is 可用于抛出错误的判断 if !errors.Is(err, os.ErrClosed) { t.Errorf("error should be equal os.ErrClosed") } // As 可以将错误检索出来 if !errors.As(err, &fbe) { t.Error("error should be matched foobarErr") } // 通过上面 As 将错误信息取出,应该可以拿到失败的任务 id if fbe.taskId != 1 { t.Error("fooErr task id should be 1") } me, isMultiError := ExportMultiError(err) if !isMultiError { t.Error("err should be a multiError") } for _, e := range me { t.Logf("range me: %v", e) var fe fooErr if errors.As(e, &fe) && fe.taskId != 1 { t.Error("variable t.taskId should be 1") } } }
补充上文使用到的 ExportMultiError
函数。
func ExportMultiError(err error) ([]error, bool) {
if err == nil {
return nil, false
}
switch err.(type) {
case multiError:
return err.(multiError), true
default:
return []error{err}, false
}
}
思考
并行处理失败的任务有无必要返回具体的信息?原库中仅透出了 errors.Is
和 errors.As
两个函数供处理异常,实际上会不会在 error
中透出具体的任务信息,供错误失败时使用呢?
基于这种思考,先提供了一个 ExportmultiError
的函数解决这个问题。有无更好的方式,或者业界更通用的处理方案?
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 [email protected]