【问题标题】:Stop a goroutine if it is running如果 goroutine 正在运行,则停止它
【发布时间】:2021-07-04 13:45:30
【问题描述】:

我有一个与How to stop a goroutine 类似的问题,但稍有不同。我不确定 goroutine 是否正在运行。

var quit = make(chan bool)

func f1() {
    go func() {
        t := time.NewTimer(time.Minute)
        select {
        case <-t.C:
            // Do stuff
        case <-quit:
            return
        }
    }()
}

func f2() {
    quit <- true
}

如果在f1() 之后不到一分钟调用了f2(),则goroutine 返回。但是,如果它在一分钟后被调用,goroutine 将已经返回,f2() 将阻塞。 我希望 f2() 在 goroutine 正在运行时取消它,否则什么也不做。

我在这里想要实现的是当且仅当它没有在创建后的一分钟内被取消时才执行任务。

说明:

  • 没有什么可以阻止f2() 被多次调用。
  • 一次只运行一个 goroutine。 f1() 的调用者将确保每分钟调用它不超过一次。

【问题讨论】:

    标签: go goroutine


    【解决方案1】:

    使用上下文。

    使用可能被取消的上下文运行f1。 使用关联的取消函数运行 f2

    func f1(ctx context.Context) {
        go func(ctx context.Context) {
            t := time.NewTimer(time.Minute)
            select {
            case <-t.C:
                // Do stuff
            case <-ctx.Done():
                return
            }
        }(ctx)
    }
    
    func f2(cancel context.CancelFunc) {
        cancel()
    }
    

    然后,为了协调这两个功能,您可以这样做:

        ctx, cancel := context.WithCancel(context.Background())
        f1(ctx)
        f2(cancel)
    

    您还可以尝试使用 context.WithTimeout 函数来合并外部定义的超时。

    如果你不知道是否有一个 goroutine 已经在运行,你可以像上面一样初始化 ctxcancel 变量,但不要将它们传递给任何东西。这避免了检查nil

    请记住将 ctx 和 cancel 视为要复制的变量,而不是引用,因为您不希望多个 goroutine 共享内存 - 这可能会导致竞争条件。

    【讨论】:

    • f1 取消后是否可以使用相同的ctx 实例再次调用或需要创建新的ctx
    • 你应该创建一个新的上下文,否则它可能已经被取消了。
    【解决方案2】:

    您可以将缓冲区大小设置为 1。这意味着您可以向它发送一个值而不会阻塞,即使该值没有立即(或根本没有)接收到。

    var quit = make(chan bool, 1)
    

    我认为最佳答案更好,这只是另一种可以转化为其他情况的解决方案。

    【讨论】:

    • 确实如此,但是下一个 goroutine 将立即退出,因为通道已经有一个元素。
    • 是的。同样的问题也适用于close(quit) 方法。该通道将永远关闭,任何后续读取都将表现相同。如果您需要单独退出每个 goroutine,它们不应共享 quit 频道。如果你想同时永久退出它们,你应该使用close(quit)
    • 我可能没有正确解释这个问题。一次只有一个 goroutine 处于活动状态,这就是为什么只有一个通道。但随后会调用f1()(在现有的 goroutine 完成之后)会创建一个新实例。
    • 重复使用退出频道是个坏主意,因为它会导致您现在遇到的各种问题。没有干净的方法可以“重置”频道。
    • 你可能是对的。不知道如何解决这个问题。无论如何感谢您的回答:)
    猜你喜欢
    • 1970-01-01
    • 2016-03-17
    • 1970-01-01
    • 1970-01-01
    • 2014-11-25
    • 1970-01-01
    • 2018-11-07
    • 2014-03-13
    • 1970-01-01
    相关资源
    最近更新 更多