独立线程中两个Tokio Runtime通过tokio::channel通信的逻辑确认
结论
你的两点理解都完全正确:
- 运行在独立线程的Tokio Runtime会各自维护线程本地的上下文实例,
tokio::spawn会自动读取当前上下文的Runtime句柄提交任务,因此first_runtime内的spawn任务会绑定到第一个Runtime执行,second_runtime内的spawn任务会绑定到第二个Runtime执行,两个Runtime的调度逻辑完全隔离。 - Tokio的mpsc有界通道的发送等待逻辑仅和缓冲区剩余空位有关:只要缓冲区还有空位,
tx.send().await就会立即完成,不会挂起发送任务,更不会阻塞发送端的线程。哪怕接收端的线程被thread::sleep完全阻塞无法消费消息,只要缓冲区没有被占满,发送操作都不会被卡住;只有当缓冲区被填满后,发送操作才会进入等待状态,直到接收端消费消息腾出空位。
代码优化建议
你的示例代码可以正常运行,但存在几个不符合Tokio最佳实践的点,可以调整:
- 不要用
#[tokio::main]注解普通异步函数:该宏的设计用途是标注程序入口,会自动在当前线程创建并启动Runtime,用它标注普通函数虽然能得到预期结果,但逻辑容易混淆。如果要在新建线程中运行独立Runtime,更推荐手动创建实例:
thread::spawn(move || { let rt = tokio::runtime::Builder::new_current_thread() .worker_threads(1) .enable_all() .build() .unwrap(); rt.block_on(first_runtime(tx)); });
- 不要在异步逻辑中使用
std::thread::sleep:该函数会阻塞整个操作系统线程,你使用的是单Worker线程的Runtime,一旦调用thread::sleep整个Runtime的所有任务都会被卡住。异步场景下请用tokio::time::sleep代替,它只会挂起当前任务,不会影响Runtime上其他任务的调度。 - 代码中
tokio::spawn(...).await的写法没有实际意义:生成异步任务后立刻await,等价于直接执行任务内部的逻辑,反而多了一层任务调度的开销,直接写内部逻辑即可。
内容的提问来源于stack exchange,提问作者Lex
相关产品推荐
相关产品推荐

