直接回答:tokio 默认多线程调度器是一个工作窃取(work-stealing)运行时:少量工作线程(默认=CPU 核数)各持本地任务队列,空闲时从别的队列偷任务。任务(spawn 的 future)在 poll 到 Pending 时让出,I/O 就绪后由 reactor(epoll/kqueue/IOCP 封装)唤醒重新排队。因为线程少而任务多,任何一个任务阻塞线程几秒,同一线程上所有任务全部饿死——这就是阻塞调用致命的机制。
展开解析:典型事故:async 代码里调用 std::fs、同步数据库驱动、thread::sleep、CPU 密集计算,整个运行时吞吐雪崩,表现为延迟毛刺且难以复现。正确姿势:阻塞 I/O 用 tokio::task::spawn_blocking 丢到独立的阻塞线程池(默认上限 512);CPU 密集任务也用 spawn_blocking 或独立线程加 channel 回传;持锁跨 await 必须用 tokio::sync::Mutex。观测手段:tokio-console 能看到每个任务的 poll 时长与位置。另一个相关概念是 yield_now:长循环里主动让出,避免霸占 worker。记住核心纪律:async 函数里的每一行代码都跑在共享的工作线程上,"快出快进"是全体的契约。
追问方向:spawn 与 spawn_blocking 的任务分别进哪个队列?tokio 的 I/O driver 与任务唤醒如何衔接?current_thread 运行时适用什么场景?
(约 460 字)