我有一个关于调度"可取消"gorouting的基本问题.

我想每3秒安排一次函数执行.

该功能最多需要5秒钟.

如果需要2999毫秒以上,我想停止/终止它,以避免与下一个重叠.

我做错了:

func main() {
    fmt.Println("开始处理")
    go 开始处理()

    time.Sleep(time.Second * 60)
    fmt.Println("endProcessing after 60s")
}

func 开始处理() {
    ticker := time.NewTicker(3 * time.Second)
    for _ = range ticker.C {
        ctx, _ := context.WithTimeout(context.Background(), (time.Second*3)-time.Millisecond)

        fmt.Println("开始剂量测量")
        doSomething(ctx)
    }
}

func doSomething(ctx context.Context) {
    executionTime := time.Duration(rand.Intn(5)+1) * time.Second

    for {
        select {
        case <-ctx.Done():
            fmt.Printf("timed out after %s\n", executionTime)
            return
        default:
            time.Sleep(executionTime)
            fmt.Printf("did something in %s\n", executionTime)
            return
        }
    }
}

这是我现在的输出:

开始处理

开始剂量测量

在2s中做了些什么

开始剂量测量

在3秒内做了些什么

开始剂量测量

在3秒内做了些什么

开始剂量测量

在5s内做了一些事情

开始剂量测量

在2s中做了些什么

...

I want to read timed out after 5s instead of 在5s内做了一些事情.

推荐答案

你只需要把time.Sleep(executionTime)放在select之外,就不需要for环了.我想这就是你想要的,但要小心.请看下面的warning.

func doSomething(ctx context.Context) {
    executionTime := time.Duration(rand.Intn(5)+1) * time.Second
    processed := make(chan int)

    go func() {
        time.Sleep(executionTime)
        processed <- 1
    }()

    select {
    case <-ctx.Done():
        fmt.Printf("timed out after %s\n", executionTime)
    case <-processed:
        fmt.Printf("did something in %s\n", executionTime)
    }
}

Obs:我把原来的答案改了一点.我们不能在执行过程中打断一个goroutine.我们可以将长时间运行的任务委托给另一个goroutine,并通过专用通道接收结果.

Warning:如果你希望处理时间超过最后期限,我不建议这样做,因为现在你会有一个泄露的goroutine.

Go相关问答推荐

如何修复Go中调用GetRawInputDeviceInfA Windows API函数时的错误?

Golang Viper:如果第一个字段不存在,如何从另一个字段获取值

GitHub发布Golang子模块

+在具有html/模板Golang的Base64中

更改位置级别和时间戳零点Golang

Go Regexp:匹配完整的单词或子字符串,或者根本不匹配

从使用Golang otelmux检测的Otel跟踪中获取trace_id

Prometheus 摘要分位数错误

使用 LINQ 对内部数组进行排序

如何使用 GolangCI 删除未使用的导入

在嵌套模板中使用变量,它也被定义为 go 模板中的变量?

Wire google Inject with multi return from provider 函数

如何将具有嵌入式 struct 的 struct 展平为 json

使用 AppID 在 Windows 中启动应用程序并获取 pid

使用 oklog/run 来自 Go 编译器的错误(无值)用作值

HCL 解码:具有多个标签的块

如何扩充 ResponseWriter 的 Header() 返回的 map

如何获得Ent中数字列的总和

如何使用 fyne 避免 GUI 应用程序中的循环依赖?

如何访问 Go 模板中数组的第一个索引的值