首页 > 解决方案 > 如何在 Tokio 中为 CPU 密集型工作创建专用线程池?

问题描述

我有一个基于Tokio运行时的 Rust 异步服务器。它必须同时处理对延迟敏感的 I/O 绑定请求和繁重的 CPU 绑定请求。

我不想让 CPU 密集型任务独占 Tokio 运行时并饿死 I/O 密集型任务,所以我想将 CPU 密集型任务卸载到一个专用的、隔离的线程池(隔离是这里的关键,所以spawn_blocking/block_in_place在一个共享线程池上是不够的)。如何在 Tokio 中创建这样的线程池?

启动两个运行时的幼稚方法会遇到错误:

线程“tokio-runtime-worker”在“无法从运行时内启动运行时”时惊慌失措。发生这种情况是因为一个函数(如block_on)在线程被用于驱动异步任务时试图阻塞当前线程。

use tokio; // 0.2.20

fn main() {
    let mut main_runtime = tokio::runtime::Runtime::new().unwrap();
    let cpu_pool = tokio::runtime::Builder::new().threaded_scheduler().build().unwrap();
    let cpu_pool = cpu_pool.handle().clone(); // this is the fix/workaround!

    main_runtime.block_on(main_runtime.spawn(async move {
        cpu_pool.spawn(async {}).await
    }))
    .unwrap().unwrap();
}

Tokio 可以允许两个单独的运行时吗?有没有更好的方法在 Tokio 中创建一个隔离的 CPU 池?

标签: rustthreadpoolrust-tokio

解决方案


虽然 Tokio 已经有一个线程池,但Tokio 的文档建议

如果您的代码受 CPU 限制并且您希望限制用于运行它的线程数,您应该在另一个线程池(例如rayon )上运行它。当人造丝任务完成时,您可以使用oneshot通道将结果发送回 Tokio 。

所以,如果你想创建一个线程池来大量使用 CPU,一个好方法是使用像 Rayon 这样的 crate 并将结果发送回 Tokio 任务。


推荐阅读