为了账号安全,请及时绑定邮箱和手机立即绑定

在 Web 应用程序中运行计划任务

在 Web 应用程序中运行计划任务

Go
MYYA 2023-07-17 14:53:02
我想每 5 分钟运行一次任务来更新网站上的统计信息,而不阻塞 HTTP 服务器。我刚刚通过工作人员示例添加了基本的 HTTP 服务器逻辑。如果我添加了这样的多个任务,这被认为是不好的做法还是有更好的方法?package mainimport (    "fmt"    "net/http"    "time")func Home(w http.ResponseWriter, r *http.Request) {    fmt.Fprintf(w, "Home page")}func schedule(f func(), interval time.Duration) *time.Ticker {    ticker := time.NewTicker(interval)    go func() {        for range ticker.C {            f()        }    }()    return ticker}func longRunningTask() {    fmt.Println("Long running task")}func main() {    schedule(longRunningTask, time.Second*5)    http.HandleFunc("/", Home)    http.ListenAndServe("127.0.0.1:8080", nil)}
查看完整描述

1 回答

?
牧羊人nacy

TA贡献1862条经验 获得超7个赞

您的实现与 Go 中的计划作业/任务非常相似。有一些类似 cron 的库可以让您更好地控制任务,但在大多数情况下,带有循环的简单 goroutine 就足够了。


以下是根据您的需求增加复杂性的更多示例:


永远运行一个任务,每次运行之间等待 5 秒。无法停止并且不考虑任务的运行时间。这是最简单的形式,也是最常见的形式。


go func() {

    for {

        task()

        <-time.After(5 * time.Second)

    }

}()

与以前相同,只是现在有一个通道可以在我们想要的时候停止任务。虽然您的实现允许您通过该方法停止任务Stop(),但 goroutine 将保持打开状态,因为通道永远不会关闭(因此会泄漏内存)。


// Includes a channel to stop the task if needed.

quit := make(chan bool, 1)


go func() {

    task()


    for {

        select {

        case <-quit:

            return

        case <-time.After(5 * time.Second):

            task()

        }

    }

}()


// To stop the task

quit <- true

这是三个解决方案中最强大的解决方案。任务可以随时停止,并且它还会考虑任务在等待再次运行时所花费的时间。在前面的示例中,如果任务运行时间为 1 秒,而您又等待 5 秒,则相对于任务启动时的时间间隔实际上是 6 秒。


该解决方案实际上仅适用于运行时间非常长的任务,或者如果您的任务以恒定的时间间隔运行至关重要。如果任务必须以恒定的时间间隔运行,那么您需要考虑到time.After()至少会等待您提供的持续时间的事实——如果 CPU 忙于其他进程/goroutines,它最终可能会等待稍长的时间。


// Calls `fn` and then waits so the total elapsed time is `interval`

func runAndWait(interval time.Duration, fn func()) {

    earlier := time.Now()

    fn()

    diff := time.Now().Sub(earlier)

    <-time.After(interval - diff)

}


quit := make(chan bool, 1)


go func() {

    // The total time to run one iteration of the task

    interval := 5 * time.Second


    for {

        select {

        case <-quit:

            return

        default:

            runAndWait(interval, task)

        }

    }

}()


查看完整回答
反对 回复 2023-07-17
  • 1 回答
  • 0 关注
  • 97 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信