使用上下文来跳出循环

Fel*_*sén 1 go go-context

考虑一下(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)
            }
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

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

我怎样才能实现这个目标?

col*_*tor 9

上下文取消并不神奇——它只是一种信号机制。要中止工作,您仍然需要监视context工作协程内的状态:

func myTask(ctx context.Context, poll time.Duration) error {                 
    ticker := time.NewTicker(poll)
    defer ticker.Stop()
                                                                 
    for {                                                                      
        fmt.Println("loop")                                                      
        select {                                                                 
        case <-ticker.C:
        case <-ctx.Done():
            return ctx.Err()
        }                                                                        
    }                                                                          
}                                                                     
                                                                         
Run Code Online (Sandbox Code Playgroud)

https://go.dev/play/p/s6dSr9qqKJU


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


跟进评论。我会像这样重构你的任务:

// 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 {
    ticker := time.NewTicker(poll)
    defer ticker.Stop()
    for {
        fmt.Println("loop")
        select {
        case <-ticker.C:
        case <-ctx.Done():
            return ctx.Err()
        }

    }
}
Run Code Online (Sandbox Code Playgroud)