golang 使用 errgroup 停止其他 goroutine

2021-09-01 10:52:15 +08:00
 Zach369

目前的需求是这样的

func main() {
	errg := new(errgroup.Group)
	errg.Go(func() error {
		return test1()
	})
	errg.Go(func() error {
		return test2()
	})
	if err := errg.Wait(); err != nil {
		log.Error(err)
	}
}

func test1() error {
	return nil
}

func test2() error {
	return errors.New("test2 err")
}

我如何控制 go 中的协程 有一个错误,其他 go 协程就不会执行? 同时大家如何控制超时的那? 希望能给个范例

2005 次点击
所在节点    Go 编程语言
9 条回复
anyxchachapoly
2021-09-01 10:57:30 +08:00
1. 其他 goroutine 就『不会执行』,还是『停止执行』,这是两件事,如果是前者,那就是 sequential 设计,如果后者,还得考量你 gorotuine 中的具体业务,部分情况可以简单使用 context ( chan )检测。

2. 超时如果不会自己设计,那就走 context 方式,如果要采用 timer 务必检查是否 drain 掉 C
anyxchachapoly
2021-09-01 11:00:13 +08:00
我上面的回答已经相当简陋,顶多是个思路指引,但对于有基础的人而言,我相信很好理解,并且也有诸多设计可以 implement

但我看了一下你的 v2 过往问题,感觉你 go 基础得好好学,别一下蹦个高楼。
caiych
2021-09-01 11:10:21 +08:00
anyxchachapoly
2021-09-01 11:12:18 +08:00
@caiych

最好的做法就是别用 errgroup,那个设计实在太基础,我们都是自己重新做一套控制
anyxchachapoly
2021-09-01 11:13:05 +08:00
@caiych

但既然你是 G 家员工,想必你们自己也有其他的做法,errgroup 或许只是个范例吧
keepeye
2021-09-01 11:13:49 +08:00
需要用到 context 包,比如你想要一个 5 秒钟超时还没执行的 goroutine 自动退出,首先初始化一个 ctx

ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)

再改造下匿名函数

err.Go(func() error {
select {
case <ctx.Done():
return errors.New("中止了")
default:
err := test1()
if err != nil {
cancel()
return err
} else {
return nil
}
}
})
darrh00
2021-09-01 11:15:53 +08:00
caiych
2021-09-01 11:17:58 +08:00
@anyxchachapoly errgroup 在 Google 里也算是最佳实践:-) 是当时 go-library team 觉得非常好用才开源出来的
lasuar
2021-09-01 12:03:09 +08:00
超时控制 context 就足够了。不会玩?
简单来说 for-select + ctx.Done(),这种方式在各种库里面是遍地开花。
多说一句,开发者不能没有侵入性的中止一个协程,都是必须在协程内监听 ctx 来自行中止的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/799216

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX