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"
至少会产生两个线程。