Go Academy · 课时

基于时间的调度

运行周期性任务

第 1 / 4 课13 个步骤

基于时间的调度 是 CoddyKit 上的免费 Go Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Go Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Go Academy 课程共包含 4 节课。

按计划运行任务

许多系统都需要定期执行任务:每晚清理临时文件、每天早晨发送摘要邮件、每分钟轮询一次 API。本课将使用标准库介绍 Go 中基于时间的任务调度。

time 包

Go 的 time 包是基础。主要工具包括:

  • time.Sleep 暂停一个协程
  • time.After 返回一个只触发一次的通道
  • time.Ticker 重复触发
  • time.Timer 在延迟后触发一次

简单循环

最简单的调度器:执行任务、休眠、重复。

package main

import (
    "fmt"
    "time"
)

func main() {
    for i := 0; i < 3; i++ {
        fmt.Println("tick", i)
        time.Sleep(10 * time.Millisecond)
    }
}

为什么 Sleep 会产生漂移

休眠循环会产生漂移:如果任务耗时 200 毫秒,休眠 1 秒,那么实际间隔就是 1.2 秒,并且误差会不断累积。要获得准确的间隔,请使用 Ticker,后续课程会介绍它。

使用 time.After 实现单次延迟

time.After(d) 返回一个通道,该通道会在时长 d 后接收一次消息。它适合在 select 中实现超时。

select {
case <-time.After(2 * time.Second):
    fmt.Println("2s elapsed")
}

time.Timer

Timer 只触发一次,并且可以停止或重置;而 time.After 无法取消。

t := time.NewTimer(5 * time.Second)
defer t.Stop()
<-t.C
fmt.Println("fired")

在特定时间调度

如果要在凌晨 3 点运行任务,请计算距离该时刻的时长,并为这段时长设置休眠或定时器,然后为第二天重新调度。

now := time.Now()
next := time.Date(now.Year(), now.Month(), now.Day(), 3, 0, 0, 0, now.Location())
if next.Before(now) {
    next = next.Add(24 * time.Hour)
}
fmt.Println("sleep for", time.Until(next))

时长具有类型

time.Duration 是以纳秒表示的 int64,并提供了方便的常量:time.Second、time.Minute、time.Hour。将它们相乘即可表示易读的时间间隔。

every := 30 * time.Minute
fmt.Println(every)

单调时钟与墙上时钟

Go 的 time.Now 包含用于测量经过时间的单调时钟读数,不受时钟调整影响。请使用 time.Since 计算时长,而不要用墙上时钟的时间相减。

start := time.Now()
// ... work ...
fmt.Println("took", time.Since(start))

何时应使用库

对于复杂的计划(例如“每个工作日 9:15”),手动编写时间计算容易出错。下一课将介绍 robfig/cron 库,它可以为您解析 cron 表达式。

可运行示例:计算下一次运行时间

这个自包含程序仅使用 time 包,计算距离下一个分钟边界还有多长时间。

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Date(2026, 1, 1, 10, 30, 45, 0, time.UTC)
    nextMinute := now.Truncate(time.Minute).Add(time.Minute)
    fmt.Println("now:", now.Format("15:04:05"))
    fmt.Println("next run:", nextMinute.Format("15:04:05"))
    fmt.Println("wait:", nextMinute.Sub(now))
}

快速检查

请测试您对基于时间的任务调度的理解。

回顾

您学习了基于时间的任务调度基础:

  • time 包提供 Sleep、After、Timer 和 Ticker
  • Sleep 循环会产生漂移;Ticker 可以保持计划
  • 使用 time.Until 计算距离目标时间的时长
  • 使用 time.Since 和单调时钟测量经过的时间
免费开始

用 AI 导师学习 Go — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
51
课程
203

常见问题解答

「基于时间的调度」课时是免费的吗?

是的 — 「基于时间的调度」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Go Academy 课程的其余内容,请升级到 CoddyKit PRO。 Go Academy 课程共包含 4 节课。

「基于时间的调度」这节课中我会学到什么?

运行周期性任务 你通过在浏览器中直接运行的动手代码来练习 Go Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Go Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Go Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「基于时间的调度」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Go Academy 课中编写并运行代码吗?

能。每节 Go Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 基于时间的调度
  2. robfig/cron 库
  3. 用于间隔执行的计时器
  4. 优雅关闭任务
← 返回 Go Academy