我需要调用一个将 Context 作为参数的函数。此代码块可以访问 channel ,该 channel 用于发信号通知应取消操作。

这是接收值时我当前用来取消Context的内容:

func doSomething(stop <-chan bool) {
    ctx, cancel := context.WithCancel(context.Background())
    go func() {
        select {
        case <-ctx.Done():
        case <-stop:
            cancel()
        }
    }()
    longRunningFunction(ctx)
}

预期的控制流程如下:
  • 如果任务运行完毕,它将取消上下文,<-ctx.Done()将触发,goroutine将终止。
  • 如果在stop上接收到一个值,则上下文将被取消,并通知任务它应该退出。再次,goroutine将在发生这种情况时终止。

  • 这似乎过于复杂。有没有更简单的方法来完成预期的行为?

    最佳答案

    正如@ain所提到的,如果longRunningFunction运行到末尾,并且stop上没有发送任何内容(或未关闭),则您的代码当前会泄漏goroutine:select语句将永远无法实现(完成context的唯一方法是当stop中出现某些内容时,调用cancel)。

    这是修复它的一种方法(主要是@ain's comment的实现):

    func doSomething(stop <-chan bool) {
        ctx := context.TODO() // because in the future, you might pass a ctx arg to this function, from which you could then "inherit"
        ctx, cancel := context.WithCancel(ctx)
        defer cancel() // to be sure to release the associated resources whatever happens (and prevent the following goroutine from leaking)
        go func() {
            select {
            case <-ctx.Done():
            case <-stop:
                cancel()
            }
        }()
        longRunningFunction(ctx)
    }
    

    关于go - 有没有更简洁的方法来创建在 channel 上接收后被取消的上下文?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43434939/

    10-16 06:00