RUST 循环调度 tokio::time::interval 与 tokio::time::sleep

循环调度 tokio::time::interval 与 tokio::time::sleep

场景设定

我们设定一个具体的场景来对比两种方式:

任务描述:

  • 每次循环中执行一个任务,该任务耗时 5 秒
  • 设置间隔为 3 秒
  • 总运行时间:20 秒

方式一:使用 interval.tick().await

示例代码:

let mut interval = tokio::time::interval(Duration::from_secs(3));
loop {
    interval.tick().await;
    println!("Task started at {:?}", Utc::now());
    tokio::time::sleep(Duration::from_secs(5)).await; // 模拟耗时任务
    println!("Task finished at {:?}", Utc::now());
}

时间线模拟:

时间(秒) 事件
0s tick() 触发,任务开始
5s 任务完成
5s 下一个 tick() 立即触发(因为已经过了 3s、6s、9s 的 tick 点)
5s 任务再次开始
10s 任务完成
10s tick() 再次触发(跳过了 9s、12s 的 tick)
10s 任务再次开始
15s 任务完成
15s tick() 再次触发
15s 任务再次开始
20s 任务完成,程序仍在运行

总结输出(假设从 0s 开始):

Task started at 0s
Task finished at 5s
Task started at 5s
Task finished at 10s
Task started at 10s
Task finished at 15s
Task started at 15s
Task finished at 20s

特点总结:

  • 任务不会等待,只要过了间隔时间点就立即开始
  • 中间的 tick 被跳过
  • 任务执行频率由时间点决定,而不是任务执行时间
  • 适合:链上事件监听、实时性要求高的场景

方式二:使用 sleep().await

示例代码:

loop {
    println!("Task started at {:?}", Utc::now());
    tokio::time::sleep(Duration::from_secs(5)).await; // 模拟任务执行
    println!("Task finished at {:?}", Utc::now());
    tokio::time::sleep(Duration::from_secs(3)).await; // 强制等待 3 秒
}

时间线模拟:

时间(秒) 事件
0s 任务开始
5s 任务完成,开始等待 3 秒
8s 等待结束,开始下一次任务
13s 任务完成,开始等待 3 秒
16s 等待结束,开始下一次任务
21s 任务完成,开始等待 3 秒

总结输出(假设从 0s 开始):

Task started at 0s
Task finished at 5s
Task started at 8s
Task finished at 13s
Task started at 16s
Task finished at 21s

特点总结:

  • 任务完成后必须等待指定时间才能开始下一次
  • 任务执行 + 等待 = 总周期时间
  • 不会跳过等待时间
  • 适合:需要防止请求过快、限制频率、任务必须完成后再等一段时间的场景

对比总结表(关键维度)

维度 interval.tick().await sleep().await
任务是否等待 ❌ 不等待,时间一到就执行 ✅ 等待任务完成后再等指定时间
是否跳过中间 tick ✅ 是的,中间的 tick 被跳过 ❌ 否,每次循环都执行
任务执行频率 ⏱ 由时间点决定 ⏳ 由任务 + 等待时间决定
是否并发执行 ❌ 不会并发 ❌ 不会并发
适合场景 实时监听、定时轮询 限速任务、提现检查、必须等待的任务
是否强制等待 ❌ 不强制 ✅ 强制等待

posted @ 2025-07-22 16:15  等你下课啊  阅读(65)  评论(0)    收藏  举报