Tokio spawn启动的no_msg_pro函数首次循环不执行问题排查
问题:Tokio异步任务延迟执行的原因
代码示例
use std::thread::sleep; use std::time; use std::sync::atomic::{AtomicU32, Ordering}; use tokio::time::Duration; static REQUEST_RECV_V2: AtomicU32 = AtomicU32::new(0); async fn no_msg_pro(s: String) { println!("exectue no_msg_pro fun - str: {} begin!", s); tokio::time::sleep(time::Duration::from_secs(5)).await; //sleep(time::Duration::from_secs(5)); println!("exectue no_msg_pro fun - str: {} end!", s); } #[tokio::main] async fn main() { tokio::spawn(async { loop { sleep(time::Duration::from_secs(10)); REQUEST_RECV_V2.fetch_add(1, Ordering::Relaxed); let s = format!("value--{:?}", REQUEST_RECV_V2); println!("run process_msg fun - handle: {:?}", s); tokio::spawn(async move { no_msg_pro(s).await; }); } }); tokio::time::sleep(Duration::from_secs(100)).await; }
运行结果
run process_msg fun - handle: "value--1" run process_msg fun - handle: "value--2" exectue no_msg_pro fun - str: value--1 begin! exectue no_msg_pro fun - str: value--1 end!
原因分析
核心问题在于错误使用了阻塞式的sleep:
- loop循环里调用的
std::thread::sleep是同步阻塞操作,会让当前线程直接暂停10秒,期间Tokio的异步调度器完全无法工作。 - Tokio默认采用单线程调度模型(
#[tokio::main]未指定多线程时),第一次进入loop后,std::thread::sleep(10秒)直接阻塞了唯一的工作线程,导致后续tokio::spawn出来的no_msg_pro任务没有机会被调度执行。 - 第一次10秒阻塞结束后,代码完成
spawn操作立刻进入第二次loop的std::thread::sleep,再次阻塞线程。直到第二次10秒结束,线程被释放,Tokio调度器才终于能处理之前堆积的no_msg_pro任务,所以此时才会执行对应"value--1"的函数。
修复方法很简单:把loop里的std::thread::sleep替换为Tokio提供的异步sleep——tokio::time::sleep(Duration::from_secs(10)).await,这样不会阻塞线程,调度器可以在等待期间正常处理其他异步任务。
内容的提问来源于stack exchange,提问作者kang wang
相关产品推荐
相关产品推荐

