You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Tokio中模拟时间:调用pause()后sleep为何未阻塞?

Tokio time::pause() 调用后sleep未按预期永久挂起的原因及解决方法

你在测试中调用tokio::time::pause()后执行10秒sleep,预期会永久挂起,但测试却完成并输出接近10秒的耗时,核心原因是**time::pause()的调用时机错误**。

原因分析

Tokio的time::pause()要求在runtime调度器启动前调用才能生效。你使用#[tokio::test]宏时,宏会先自动初始化并启动runtime,再执行测试函数内的代码。当time::pause()在测试函数里执行时,时间调度机制已经处于正常运行状态,此时调用pause不会产生预期的暂停效果,sleep仍会按照真实时间推进。

解决方法

有两种可行的修正方式:

1. 使用#[tokio::test]的start_paused参数(Tokio 1.16+支持)

直接在测试宏中开启启动时暂停时间的配置,无需手动调用time::pause():

use tokio::time;
use tokio::time::{Instant, Duration};

#[tokio::test(flavor = "current_thread", start_paused = true)]
async fn pause_time() {
    let i0 = Instant::now();
    time::sleep(Duration::from_secs(10)).await;
    let i1 = Instant::now();
    println!("{:?}", i1-i0); // 此时会输出接近0的耗时,时间被暂停后sleep不会等待真实时间
}

2. 手动创建Runtime并在启动前调用time::pause()

通过tokio::runtime::Builder手动构建runtime,确保在启动前调用pause:

use tokio::runtime::Builder;
use tokio::time;
use tokio::time::{Instant, Duration};

fn main() {
    let runtime = Builder::new_current_thread()
        .enable_time()
        .build()
        .unwrap();
    
    // 必须在启动runtime前调用pause
    time::pause();
    
    runtime.block_on(async {
        let i0 = Instant::now();
        time::sleep(Duration::from_secs(10)).await;
        let i1 = Instant::now();
        println!("{:?}", i1-i0); // 输出接近0的耗时
    });
}

补充说明

当时间被暂停后,Instant::now()会返回固定值,只有通过time::advance()主动推进时间,或者当runtime没有待执行任务时才会自动推进时间。如果需要让sleep完成,你需要手动调用time::advance(Duration::from_secs(10))来推进时间。

内容的提问来源于stack exchange,提问作者Victor Ermolaev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 13:55:03