如何使用通道通知goroutine正确退出

如何使用通道通知goroutine正确退出,go,Go,注意:我用谷歌搜索了这个主题,阅读了几乎所有我能找到的内容,但仍然无法得到正确/合理/适合生产的答案 基本上所有的答案都是相似的,就像这一个:,都在相同的模式中,没有例外:真正的工作是fmt.Println(1)打印一些东西,或者只是//做其他事情 但是如果将实际工作保持在selectdefaultcase分支的,那么它将被执行多次,以便打印一些内容,这是正常的,但显然它还没有准备好进行实际工作 我能想象的唯一有效的方法是将实际工作放在案例分支上,然后只向该案例发送一个信号,通知其开始,如下图所

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

基本上所有的答案都是相似的,就像这一个:,都在相同的模式中,没有例外:真正的工作是
fmt.Println(1)
打印一些东西,或者只是
//做其他事情

但是如果将实际工作保持在selectdefaultcase分支的
,那么它将被执行多次,以便打印一些内容,这是正常的,但显然它还没有准备好进行实际工作

我能想象的唯一有效的方法是将实际工作放在案例分支上,然后只向该案例发送一个信号,通知其开始,如下图所示:,但也感觉到紧张,这种方法是否会潜在地产生一些问题


添加了代码片段以准确显示我试图实现的目标:,我希望在客户端关闭连接时实现,然后立即终止我的处理程序,释放资源,并无条件退出。

而不是使用
选择
循环,您要在多个位置检查取消信号。但是为了不阻塞,您仍然必须使用
选择
(默认情况下为空),这使得它有点不正确。我使用的是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")
}
func-doWork(ctx-context.context){
fmt.Println(“做一些工作1”)
时间。睡眠(时间。秒*5)
//检查任务是否已取消
挑选{

如果您不想多次执行某个内容,那么就不要这样做。如果您想对通过通道接收的每个值执行某个内容一次,那么您的示例工作正常。我不确定实际问题是什么。请注意,在您的示例中,通常只需关闭通道来向goroutine发送信号:尽管如果您只想关闭通道o让某个东西执行一次,尝试某种形式的取消有什么意义?使用
sync
包(
sync.once
)使某些内容只执行一次。将其与其他通道逻辑结合使用,可以使某个通道只发出一次信号。@Inshi,关键是如果您只执行一次内容,则无需退出,因为您可以在工作完成后立即返回。@lnshi,您不能中断阻塞调用。您需要r等待它完成,或者重写它以便它可以被中断。这是通常使用的。感谢您的回答,多个检查点,我认为我们不应该在生产中使用类似的代码:)如果您希望能够“在取消时”放弃冗长的任务除了在任务中选择有意义的点来检查取消信号并采取适当行动(即返回而不完成任务的其余部分)之外,没有其他方法。