About #[tokio::test]

#[tokio::test] 运行时

#[tokio::test] 运行时和 #[tokio::main] 的默认值是不一样的,前者默认单线程,后者默认多线程:

The default test runtime is single-threaded.

所以有的时候运行和测试的结果可能不同。

可以设置为多线程的风格:

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn my_test() {
    assert!(true);
}

如何不同?

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn test() {
    let rc = std::sync::Arc::new(tokio::sync::Mutex::new(false));
    let executed = rc.clone();
    let mut join_handle = tokio::spawn(async move {
        println!("task running");
        *executed.lock().await = true;
        std::future::pending::<()>().await;
    });
    let executed = rc.clone();
    assert!(!*executed.lock().await); // 一般来说,就算是多线程环境下 task 也还没能运行
    // let _ = tokio::task::yield_now().await; // 在单线程下,必须主动 await 释放执行权,task 才能被安排运行
    join_handle.abort();
    assert!((&mut join_handle).await.unwrap_err().is_cancelled());
}

搞啰嗦了,简单点:

#[tokio::test]
async fn test() {
    let rc = std::sync::Arc::new(tokio::sync::Mutex::new(false));
    let executed = rc.clone();
    let join_handle = tokio::spawn(async move {
        println!("task running");
        *executed.lock().await = true;
        std::future::pending::<()>().await;
    });
    let executed = rc.clone();
    loop {
        let v = *executed.lock().await;
        println!("{v}");
        sleep(2000).await;
    }
}

// 输出:
running 1 test
false
task running
true
true

这段代码如果没有对锁进行 await,那么在单线程下的输出不可能是 true。(致敬不确定性原理、AKA 测不准原理)

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]

#[tokio::test(flavor = "multi_thread", worker_threads = 1)] 真的是单线程的吗?不是,因为下面两个测试都会执行task:

#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
async fn test() {
    let rc = std::sync::Arc::new(tokio::sync::Mutex::new(false));
    let executed = rc.clone();
    let join_handle = tokio::spawn(async move {
        println!("task running");
        *executed.lock().await = true;
        std::future::pending::<()>().await;
    });
    std::thread::sleep(std::time::Duration::from_millis(8000));
}

#[tokio::test]
async fn test() {
    let rc = std::sync::Arc::new(tokio::sync::Mutex::new(false));
    let executed = rc.clone();
    let join_handle = tokio::spawn(async move {
        println!("task running");
        *executed.lock().await = true;
        std::future::pending::<()>().await;
    });
    let _ = tokio::task::yield_now().await;
    std::thread::sleep(std::time::Duration::from_millis(4000));
}

所以说 worker_threads 是指除了调度器主线程以外的工作线程数量,也就是说 flavor = "multi_thread" 至少会产生两个线程。

posted @ 2023-05-19 16:14  develon  阅读(401)  评论(0编辑  收藏  举报