首页 > 解决方案 > 如何从长时间运行的 goroutine 发送更新?

问题描述

我有一个长期工作的 goroutine。工作完成后,它将结果推送到通道。同时,在作业运行时,我想继续更新状态为 RUNNING 的 API。

到目前为止,我有以下代码:

func getProgressTimeout() <-chan time.Time {
    return time.After(5 * time.Minute)
}

func runCommand(arg *Request) {
    chanResult := make(chan Results)

    go func(args *Request, c chan Results) {
        resp, err := execCommand(args)
        c <- Results{
            resp: resp,
            err:  err,
        }
    }(arg, chanResult)

    var err error

progressLoop:
    for {
        select {
        case <-getProgressTimeout():
            updateProgress()  // this method will send status= RUNNING to a REST API

        case out := <-chanResult:
            err = jobCompleted(request, out)
            break progressLoop
        }
    }
    return err
}

我是golang的新手。经过大量的反复试验和谷歌搜索,我已经达到了上面的代码。它现在正在工作。当我看到它时,我仍然觉得它并不直观(这很可能是因为,我仍在尝试学习 Go 的做事方式)。所以我的问题是,我可以将其重构为更好的形状吗?是否有一些适用于这种场景的现有模式?或者,如果有一些完全不同的方法可以在作业运行时继续发送定期更新?

此外,任何改进我的 golang 并发性的建议也值得赞赏。:)

提前致谢!

标签: go

解决方案


考虑使用time.NewTicker,它将周期性值发送到通道。这是文档中的一个示例:

package main

import (
    "fmt"
    "time"
)

func main() {
    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()
    done := make(chan bool)
    go func() {
        time.Sleep(10 * time.Second)
        done <- true
    }()
    for {
        select {
        case <-done:
            fmt.Println("Done!")
            return
        case t := <-ticker.C:
            fmt.Println("Current time: ", t)
        }
    }
}

请注意,嵌入式 goroutine 调用func通过休眠 10 秒来模拟一个长任务,而调用者用于select等待结果,同时还接收来自股票的周期性事件 - 这是您可以进行 API 进度更新的地方。


推荐阅读