Golang 开源之 semgroup 使用指南

  1. 使用方法
  2. 思考

semgroup 用于并发执行一组任务,提供限制协程数量、同步等待任务执行完成及错误信息传递的能力。不同于 errgroup ,semgroup 会执行所有任务,且收集任务产生的 error 信息。在全部任务执行完成后,将收集的 error 信息返回给开发者。

使用方法

快速使用请看官网的使用方法,此处不赘述

示例 TestDemo 中用到了如下功能,可以按需使用

  1. context 定义了超时时间,可以限制整个任务的执行时间

  2. 任务并行执行,且向外丢出了自定义 error

  3. 使用 errors.Iserrors.As 处理 error

  4. 使用了拓展的 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.Iserrors.As 两个函数供处理异常,实际上会不会在 error 中透出具体的任务信息,供错误失败时使用呢?
基于这种思考,先提供了一个 ExportmultiError 的函数解决这个问题。有无更好的方式,或者业界更通用的处理方案?


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 nickchenyx@gmail.com

Title:Golang 开源之 semgroup 使用指南

Count:642

Author:nickChen

Created At:2022-05-24, 11:32:21

Updated At:2023-05-08, 23:27:10

Url:http://nickchenyx.github.io/2022/05/24/golang-semgroup-usage/

Copyright: 'Attribution-non-commercial-shared in the same way 4.0' Reprint please keep the original link and author.