Golang Go语言中使用 errgroup 停止其他 goroutine

发布于 1周前 作者 yibo5220 来自 Go语言

Golang Go语言中使用 errgroup 停止其他 goroutine

目前的需求是这样的

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 协程就不会执行? 同时大家如何控制超时的那? 希望能给个范例


更多关于Golang Go语言中使用 errgroup 停止其他 goroutine的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

10 回复
  1. 其他 goroutine 就『不会执行』,还是『停止执行』,这是两件事,如果是前者,那就是 sequential 设计,如果后者,还得考量你 gorotuine 中的具体业务,部分情况可以简单使用 context ( chan )检测。

    2. 超时如果不会自己设计,那就走 context 方式,如果要采用 timer 务必检查是否 drain 掉 C

更多关于Golang Go语言中使用 errgroup 停止其他 goroutine的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我上面的回答已经相当简陋,顶多是个思路指引,但对于有基础的人而言,我相信很好理解,并且也有诸多设计可以 implement

但我看了一下你的 v2 过往问题,感觉你 go 基础得好好学,别一下蹦个高楼。



最好的做法就是别用 errgroup,那个设计实在太基础,我们都是自己重新做一套控制



但既然你是 G 家员工,想必你们自己也有其他的做法,errgroup 或许只是个范例吧

需要用到 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
}
}
})

errgroup 在 Google 里也算是最佳实践:-) 是当时 go-library team 觉得非常好用才开源出来的

超时控制 context 就足够了。不会玩?
简单来说 for-select + ctx.Done(),这种方式在各种库里面是遍地开花。
多说一句,开发者不能没有侵入性的中止一个协程,都是必须在协程内监听 ctx 来自行中止的。

在Golang中,errgroup是一个非常有用的包,它简化了在多个goroutine中处理错误和同步的工作。当你需要在一个goroutine中遇到错误时停止其他goroutine,errgroup提供了一种简洁的方法来实现这一点。

errgroup.Group结构体提供了一个Go方法,用于启动新的goroutine,并且所有由这个Group启动的goroutine都会共享一个公共的错误通道。一旦其中一个goroutine返回了错误,GroupWait方法将立即返回这个错误,并且你可以使用这个机制来停止其他还在运行的goroutine。

这里是一个简单的示例:

package main

import (
    "context"
    "errors"
    "fmt"
    "time"

    "golang.org/x/sync/errgroup"
)

func main() {
    g, ctx := errgroup.WithContext(context.Background())

    g.Go(func() error {
        // 模拟一个错误
        time.Sleep(1 * time.Second)
        return errors.New("something went wrong")
    })

    g.Go(func() error {
        // 检查上下文是否已经被取消
        select {
        case <-ctx.Done():
            return ctx.Err()
        case <-time.After(2 * time.Second):
            return nil
        }
    })

    if err := g.Wait(); err != nil {
        fmt.Println("Error:", err)
    }
}

在这个示例中,一旦第一个goroutine返回错误,第二个goroutine将通过检查ctx.Done()来感知到这个错误,并相应地停止自己的工作。

回到顶部