简体   繁体   English

使用 errgroup 终止阻塞 goroutine

[英]terminating blocking goroutines with errgroup

I have two tasks that are running in go routines.我有两个任务在 go 例程中运行。 I am using errgroup.我正在使用错误组。 I am not sure how to use the errgroup.WithContext correctly.我不确定如何正确使用 errgroup.WithContext。

In the following code, task1 is returning the error and I would like to terminate task2 (long running) when that happens.在下面的代码中,task1 正在返回错误,我想在发生这种情况时终止 task2(长时间运行)。 Please note that in this example time.sleep is added just to simulate my problem.请注意,在此示例中添加 time.sleep 只是为了模拟我的问题。 In reality task1 and task2 are doing real work and does not have any sleep call.实际上 task1 和 task2 正在做真正的工作并且没有任何睡眠呼叫。

package main

import (
    "context"
    "fmt"
    "golang.org/x/sync/errgroup"
    "time"
)

func task1(ctx context.Context) error {
    time.Sleep(5 * time.Second)
    fmt.Println("first finished, pretend error happened")
    return ctx.Err()
}

func task2(ctx context.Context) error {
    select {
    case <-ctx.Done():
        fmt.Println("task 1 is finished with error")
        return ctx.Err()
    default:
        fmt.Println("second started")
        time.Sleep(50 * time.Second)
        fmt.Println("second finished")
    }
    return nil
}

func test() (err error) {
    ctx := context.Background()
    g, gctx := errgroup.WithContext(ctx)

    g.Go(func() error {
        return task1(gctx)
    })

    g.Go(func() error {
        return task2(gctx)
    })

    err = g.Wait()
    if err != nil {
        fmt.Println("wait done")
    }

    return err
}

func main() {
    fmt.Println("main")
    err := test()
    if err != nil {
        fmt.Println("main err")
        fmt.Println(err.Error())
    }
}


It's up to your tasks to handle context cancellation properly and not time.Sleep inside a select.正确处理上下文取消而不是时间取决于您的任务。在time.Sleep中睡觉。

As stated in errgroup documentation:如 errgroup 文档中所述:

WithContext returns a new Group and an associated Context derived from ctx. WithContext 返回一个新组和一个从 ctx 派生的关联上下文。

The derived Context is canceled the first time a function passed to Go returns a non-nil error or the first time Wait returns, whichever occurs first.派生的上下文在第一次传递给 Go 的 function 返回非零错误或第一次 Wait 返回时被取消,以先发生者为准。

You are using error group right, but it's your context handling that needs a refactor.您正在使用错误组,但您的上下文处理需要重构。

Here is a refacor of your task 2:这是您的任务 2 的重构:

func task2(ctx context.Context) error {
    errCh := make(chan bool)

    go func() {
        time.Sleep(50 * time.Second)
        errCh <- true
    }()

    select {
    case <-ctx.Done():
        return fmt.Errorf("context done: %w", ctx.Err())
    case <-errCh:
        return errors.New("task 2 failed")
    }
}

With such select, you wait for the first channel to emit.使用这样的 select,您等待第一个通道发射。 In this case, it is the context expiration, unless you modify time sleep to be lower.在这种情况下,它是上下文过期,除非您将 time sleep 修改为更低。 Example playground .示例游乐场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 嵌套在一堆 goroutine 中的 errgroup - Nested errgroup inside bunch of goroutines 使用 errgroup 在第一个错误时取消 goroutines - Cancel goroutines on first error using errgroup GoRoutines在Golang中的阻止行为 - Blocking Behaviour of GoRoutines in Golang goroutines中的golang计时器阻止 - golang timer blocking in goroutines 防止 main() 函数在 Golang 中的 goroutines 完成之前终止 - Prevent the main() function from terminating before goroutines finish in Golang 没有通道的 golang errgroup 示例 - golang errgroup example without channels golang 中的 errgroup 的使用有限制吗? - Is errgroup in golang restrictive in its usage? 为了避免在 Go 网络应用程序处理程序中多个数据库调用相互阻塞,goroutines + syncGroup 是唯一的方法吗? - To avoid multiple database calls blocking each other in a Go web app handler, are goroutines + syncGroup the only way? 如果goroutines涉及用户空间线程,阻塞操作是否可以导致整个线程的上下文切换? - If goroutines involve userspace threads, can a blocking operation leads to context switch of the entire thread? 如何使用 for 循环在多个 goroutines 之间进行通信,并在其中一个阻塞函数调用 - How to communicate between multiple goroutines with for loops with blocking function calls inside one of them
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM