1 / 24

Learn Design and Implementation Principles through Sync Errgroup Source Code Reading

This article explores the source code of sync errgroup, a Go package for handling a group of goroutines, and discusses its design and implementation principles. It also provides examples and tips for using sync errgroup effectively in real-world scenarios.

tgordon
Download Presentation

Learn Design and Implementation Principles through Sync Errgroup Source Code Reading

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. sync.errgroup 源码阅读 mai 2019-07-15

  2. 自我介绍 个人 • POP IM 后端负责人 • Go 夜读发起人 • TUG 华南区负责人 因缘 • 从 Go 源码阅读中学习设计和实现原理 • 更多 reading-go 我能提供的 • Go 夜读持续阅读分享 • Go 实战经验交流 • 帮助更多的开发者 • TiDB User Group 用户生态 我想获得的 • Go 技术提升 • Go 实战经验 • 用户和开发者

  3. 目录 • sync.errgroup 的由来 • sync.errgroup 的示例 • sync.errgroup 源码阅读 • sync.errgroup 延展 kratos/pkg/sync/errgroup • sync.errgroup 开源项目使用情况 • Q&A

  4. WaitGroup 处理并发任务 创建 goroutine ,开始任务调用 wg.Add(1); 任务结束,调用 wg.Done(); 等待所有任务完成,调用 wg.Wait()

  5. WaitGroup 的问题 当我们的 goroutine 出错了,我们怎么知道出错的原因呢?

  6. sync.errgroup 的由来 errgroup 是为了处理一组任务的子任务的 goroutine 组,它提供同步、错误传递和上下文取消。

  7. 听不懂啊! 你有一组任务是并发的工作,当遇到某种错误或者你不想再输出了,你可能想取消整个 goroutine,那么 errgroup.errgroup 就是为你而设计的。

  8. 目录 • sync.errgroup 的由来 • sync.errgroup 的示例 • sync.errgroup 源码阅读 • sync.errgroup 延展 kratos/pkg/sync/errgroup • sync.errgroup 开源项目使用情况 • Q&A

  9. 示例:并发爬虫 var g errgroup.Group var urls = []string{ "http://www.baidu.com/", "http://www.baidu.com/", "http://www.1234567.com/",//假的 } for _, url := range urls { // Launch a goroutine to fetch the URL. url := url g.Go(func() error { // Fetch the URL. resp, err := http.Get(url) if err == nil { // 这里记得关掉 resp.Body.Close() } // .. 这里可以做一些 resp 的处理 return err }) } // Wait for all HTTP fetches to complete. err := g.Wait(); if err != nil { fmt.Printf("err: %v", err) return } fmt.Println("Successfully fetched all URLs.") 协程内出错并不会影响其他协程的的处理

  10. 目录 • sync.errgroup 的由来 • sync.errgroup 的示例 • sync.errgroup 源码阅读 • sync.errgroup 延展 kratos/pkg/sync/errgroup • sync.errgroup 开源项目使用情况 • Q&A

  11. sync.errgroup 源码阅读 // Group 是处理同一总体任务的子任务的 goroutines 集合 type Group struct { cancel func() // context 中的 cancel wg sync.WaitGroup // 多个任务调度 errOnce sync.Once // 每个只执行一次 err error } // WithContext 返回一个从 ctx 派生的 context 的新的 Group // 当函数第一次传递给 Go 时,派生 context 被取消,返回非零错误或第一次 Wait 返回,以发生者为优先。 func WithContext(ctx context.Context) (*Group, context.Context) { ctx, cancel := context.WithCancel(ctx) return &Group{cancel: cancel}, ctx }

  12. sync.errgroup 源码阅读 // 利用 waitGroup 的 wait func (g *Group) Wait() error { g.wg.Wait() if g.cancel != nil { g.cancel() } return g.err } ...

  13. sync.errgroup 源码阅读 // Go 在一个新的 goroutine 里面调用给的 function // 第一次调用返回一个非零值 error,它的错误将会被返回在 Wait func (g *Group) Go(f func() error) { g.wg.Add(1) go func() { defer g.wg.Done() if err:= f(), err != nil { // 只会执行一次,一旦遇到错误,就停止总任务 g.errOnce.Do(func(){ g.err = err if g.cancel != nil { g.cancel() } }) } }() }

  14. 目录 • sync.errgroup 的由来 • sync.errgroup 的示例 • sync.errgroup 源码阅读 • sync.errgroup 延展 kratos/pkg/sync/errgroup • sync.errgroup 开源项目使用情况 • Q&A

  15. kratos 之 sync/errgroup 提供带 recover 和并行数的 errgroup,err 中包含详细堆栈信息。

  16. kratos 之 sync/errgroup 使用 见 errgroup/doc.go

  17. kratos 的 pkg/sync/errgroup typeGroupstruct { err error wg sync.WaitGroup errOnce sync.Once workerOnce sync.Once ch chanfunc(ctx context.Context) error chs []func(ctx context.Context) error ctx context.Context cancel func() } 底色部分为 kratos 相对于 sync/errgroup 新增

  18. kratos pkg/sync/errgroup 获取堆栈信息 deferfunc() { if r :=recover(); r != nil { buf :=make([]byte, 64<<10) buf = buf[:runtime.Stack(buf, false)] err = fmt.Errorf("errgroup: panic recovered: %s\n%s", r, buf) } if err != nil { g.errOnce.Do(func() { g.err = err if g.cancel != nil { g.cancel() } }) } g.wg.Done() // 因为是并发,所以这里需要捕获并执行 Done() }()

  19. 目录 • sync.errgroup 的由来 • sync.errgroup 的示例 • sync.errgroup 源码阅读 • sync.errgroup 延展 kratos/pkg/sync/errgroup • sync.errgroup 开源项目使用情况 • Q&A

  20. 开源项目使用情况 • 基于 errgroup 的封装 https://godoc.org/github.com/cockroachdb/cockroach/pkg/util/ctxgroup • https://godoc.org/github.com/coreos/etcdlabs/cluster • https://godoc.org/github.com/docker/containerd/fs • https://godoc.org/github.com/grafana/grafana/pkg/tsdb/cloudwatch • https://godoc.org/github.com/knative/serving/pkg/pool • https://godoc.org/github.com/kubernetes/minikube/pkg/minikube/bootstrapper/kubeadm

  21. 开源项目使用情况 #etcdlabs/cluster/cluster.go // WaitForLeader waits for cluster to elect a new leader. func (clus *Cluster) WaitForLeader() error { lg.Info("wait for leader election") var g errgroup.Group for i := 0; i < clus.size; i++ { idx := i g.Go(func() error { return clus.Members[idx].WaitForLeader() }) } if gerr := g.Wait(); gerr != nil { return gerr } lg.Info("waited for leader election") … }

  22. 参考资料 • https://godoc.org/golang.org/x/sync/errgroup • https://studygolang.com/articles/4189 • x/sync/errgroup: get all errors https://github.com/golang/go/issues/23595

  23. Go 夜读的成长离不开大家的支持! 希望你可以给予真实的反馈! 问卷调查

  24. Q&A Thanks!

More Related