Rust基于Tokio多线程运行异步任务及panic报错排查
问题原因
触发该panic的核心逻辑如下:
#[tokio::main]宏会自动生成一个全局的Tokio运行时,将标记的async main函数作为运行时内的初始任务执行,也就是说你的main函数本身已经运行在异步上下文里。- 你在这个异步上下文内部又手动通过
Builder::new_multi_thread()构建了第二个独立的Tokio运行时rt。 - Tokio运行时在drop(析构)时会阻塞等待自身持有的所有任务完成、完成全部资源回收,这个阻塞操作不允许在异步上下文中执行。
- 你没有手动对
rt做关闭处理,当main函数执行到末尾时,rt会自动离开作用域触发析构,刚好命中了“异步上下文内阻塞drop运行时”的报错条件。
报错信息里的
Cannot drop a runtime in a context where blocking is not allowed就是对这个场景的直接描述。
修复方式
根据你的需求二选一即可:
- 如果不需要自定义工作线程数这类特殊运行时配置,直接使用
#[tokio::main]生成的默认运行时即可,不需要手动新建第二个rt,提交任务直接调用全局的tokio::spawn:
async fn routine(millis: u64) { tokio::time::sleep(std::time::Duration::from_millis(millis)).await; } #[tokio::main] async fn main() { let handles: Vec<tokio::task::JoinHandle<_>> = (1..10_u64).map(|i| { tokio::spawn(routine(i)) }).collect(); for handle in handles { handle.await.unwrap(); } }
- 如果确实需要自定义运行时参数(比如指定2个工作线程),就去掉
#[tokio::main]宏,在同步的main函数入口手动构建运行时,保证运行时的析构发生在同步上下文:
async fn routine(millis: u64) { tokio::time::sleep(std::time::Duration::from_millis(millis)).await; } fn main() { let rt = tokio::runtime::Builder::new_multi_thread() .worker_threads(2) .enable_all() .build() .unwrap(); // 通过block_on在自定义运行时上执行异步逻辑 rt.block_on(async { let handles: Vec<tokio::task::JoinHandle<_>> = (1..10_u64).map(|i| { tokio::spawn(routine(i)) }).collect(); for handle in handles { handle.await.unwrap(); } }); // 此处rt离开作用域析构,处于同步上下文,不会触发panic }
内容的提问来源于stack exchange,提问作者Yoskutik
相关产品推荐
相关产品推荐

