【问题标题】:How to use channel to notify a goroutine to quit properly如何使用通道通知 goroutine 正确退出
【发布时间】:2023-04-02 15:53:01
【问题描述】:

注意:我用谷歌搜索了这个主题,几乎阅读了我能找到的所有内容,但仍然无法获得正确/合理/生产就绪的答案。

基本上所有的答案都是相似的,就像这个:how to stop a groutine,都是相同的模式,没有例外:真正的工作是fmt.Println(1)打印一些东西,或者只是// Do other stuff,

但是如果将实际工作保留在for select default case branch,那么它将被执行多次,打印一些东西是可以的,但显然它还没有准备好进行实际工作。

我能想象的唯一有效方法是将真正的工作放在案例分支上,然后向该案例发送 only 一个 信号以通知它开始,就像这里:playground,但只是感觉想,同样使用这种方法,它是否会产生一些潜在的问题?

添加代码片段以准确显示我想要实现的目标:https://play.golang.org/p/7xjjiW7XdoQ,我想在客户端关闭连接时实现,然后立即终止我的处理程序,释放资源,然后无条件退出。

【问题讨论】:

  • 如果您不想多次执行某项操作,请不要这样做。如果您想通过通道接收到的每个值执行一次,那么您的示例可以正常工作。我不确定实际的问题是什么。
  • 请注意,在您的示例中,通常只会通过关闭通道来向 goroutine 发出信号:play.golang.org/p/svrXcmiHymx 虽然如果您只打算执行一次,那么尝试某种类型的意义何在取消?
  • 使用sync 包(特别是sync.Once)有一些只会执行一次的东西。将其与其他通道逻辑结合使用,以获得一个仅发出一次信号的通道。
  • @Inshi,关键是如果你只执行一次,没有什么可以退出的,因为你可以在工作完成后立即返回。
  • @lnshi,您不能中断阻塞调用。您要么等待它完成,要么重写它以便可以中断它。这就是Context 通常的用途。

标签: go


【解决方案1】:

您希望在多个位置检查取消信号,而不是使用for select 循环。但是为了不阻塞,您仍然必须使用select(默认情况为空),这使它有点尴尬。我使用的是 context.Context 而不是“普通取消通道”,但想法是一样的:

func doWork(ctx context.Context) {
    fmt.Println("Doing some work 1")
    time.Sleep(time.Second * 5)
    // check is the task cancelled
    select {
    case <-ctx.Done():
        fmt.Println("cancelled at checkpoint 1")
        return
    default:
    }
    fmt.Println("Doing some work 2")
    time.Sleep(time.Second * 5)
    // check is the task cancelled
    select {
    case <-ctx.Done():
        fmt.Println("cancelled at checkpoint 2")
        return
    default:
    }
    fmt.Println("Doing some work 3")
    time.Sleep(time.Second * 5)
}

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
    defer cancel()
    go func() {
        doWork(ctx)
        wg.Done()
    }()
    wg.Wait()
    fmt.Println("done")
}

【讨论】:

  • 感谢您的回答,多个检查点,我认为我们不应该在生产中使用类似的代码 :)
  • 如果您希望“无论何时取消”都能够放弃冗长的任务,除了选择任务中有意义的点来检查取消信号并采取适当的行动之外,别无他法(即返回而不完成其余任务)。
猜你喜欢
  • 2013-02-28
  • 2019-11-04
  • 2018-10-23
  • 1970-01-01
  • 2013-03-20
  • 1970-01-01
  • 1970-01-01
  • 2020-08-02
  • 1970-01-01
相关资源
最近更新 更多