如何使用频道通知goroutine正常退出

时间:2018-05-23 13:21:34

标签: go

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

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

但如果将实际工作保持在for select default case branch,那么它将被执行多次,以便打印好的东西,但很明显它还没有为实际工作做好准备。

我能想象的唯一有效方法是将实际工作放在案例分支上,然后将仅一个信号发送到该案例以通知它开始,例如:playground,但是只是感到烦恼,也有这种方法,它是否可能产生一些问题?

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

1 个答案:

答案 0 :(得分:0)

您想要在多个位置检查取消信号,而不是使用for select循环。但是为了不阻止你仍然必须使用select(空的默认情况)这使得它有点笨拙。我正在使用context.Context而不是“plain cancel channel”,但想法是一样的:

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")
}