使用上下文跳出循环

Posted

技术标签:

【中文标题】使用上下文跳出循环【英文标题】:Use context to break out of a loop 【发布时间】:2021-07-31 20:48:03 【问题描述】:

考虑一下(https://play.golang.org/p/zvDiwul9QR0):

package main

import (
    "context"
    "fmt"
    "time"
)

func main() 
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()
    for 
        select 
        case <-ctx.Done():
            fmt.Println("Done")
            break
        default:
            for 
                fmt.Println("loop")
                time.Sleep(500 * time.Millisecond)
            
        

    

所以这里的上下文会在 2 秒后返回一个“Done()”通道。我想抓住这个并取消我的无限 for 循环。上面的代码示例没有这样做,它永远不会退出循环。

我怎样才能做到这一点?

【问题讨论】:

【参考方案1】:

上下文取消不是魔术——它们只是一种信号机制。要中止工作,您需要从您的工作 goroutine 监控 context 的状态:

for 
    fmt.Println("loop")
    select 
        case <-time.After(500 * time.Millisecond):
        case <-ctx.Done():
            return
    

https://play.golang.org/p/L6-nDpo9chb


也正如 Eli 指出的那样,break 只会跳出 select 语句 - 所以你需要更精确的东西来跳出循环。重构为函数使return 的任务中止更加直观。


从 cmets 跟进。我会像这样重构你的任务:

// any potentially blocking task should take a context
// style: context should be the first passed in parameter
func myTask(ctx context.Context, poll time.Duration) error 
    for 
        fmt.Println("loop")
        select 
        case <-time.After(poll):
        case <-ctx.Done():
            return ctx.Err()
        

    

https://play.golang.org/p/I3WDVd1uHbz

【讨论】:

谢谢!所以我需要在我的循环中嵌入另一个选择语句? @FelixRosén 我已经更新了关于如何在风格上编写一个需要上下文的任务的答案。

以上是关于使用上下文跳出循环的主要内容,如果未能解决你的问题,请参考以下文章

在JAVA中如何跳出当前的多重嵌套循环?

JS循环及跳出循环总结

JS循环及跳出循环总结

Python跳出循环语句continue与break的区别

Js跳出循环

如果有多个循环,在最内层里用break语句是是跳出最内层循环还是跳出所有循环