Skip to content

线程池:ComputeTaskPool、AsyncComputeTaskPool、IoTaskPool

Bevy 维护三个全局线程池,各有分工:

用途特点
ComputeTaskPoolCPU 密集型计算任务应在当帧完成
AsyncComputeTaskPool可跨帧的重计算任务可以跑多帧
IoTaskPoolI/O 密集型操作任务大部分时间在等待

三个池都是 TaskPool 的 newtype,通过 ::get() 获取全局实例。它们在 DefaultPlugins 初始化时自动创建。

TaskPool::scope:并行分治

scope 把一组任务分发到线程池,等待全部完成后收集结果:

rust
use bevy::prelude::*;
use bevy::tasks::ComputeTaskPool;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .add_systems(Update, parallel_work)
        .run();
}

fn setup() {
    info!("TaskPool 基础用法:并行计算素数");
}

fn parallel_work(mut ran: Local<bool>) {
    if *ran {
        return;
    }
    *ran = true;

    let pool = ComputeTaskPool::get();
    let numbers: Vec<u64> = (2..100_000).collect();

    let results = pool.scope(|scope| {
        for chunk in numbers.chunks(1000) {
            let chunk = chunk.to_vec();
            scope.spawn(async move {
                chunk
                    .into_iter()
                    .filter(|&n| is_prime(n))
                    .collect::<Vec<_>>()
            });
        }
    });

    let total: usize = results.iter().map(|v| v.len()).sum();
    info!("2..100000 中共找到 {total} 个素数");
}

fn is_prime(n: u64) -> bool {
    if n < 2 {
        return false;
    }
    if n < 4 {
        return true;
    }
    if n % 2 == 0 || n % 3 == 0 {
        return false;
    }
    let mut i = 5;
    while i * i <= n {
        if n % i == 0 || n % (i + 2) == 0 {
            return false;
        }
        i += 6;
    }
    true
}

Listing 34-1:TaskPool::scope——并行计算素数

scope 接受一个闭包,闭包接收 &Scope,通过 scope.spawn(async { ... }) 提交任务。所有任务完成后,scope 返回 Vec<T>——每个任务的输出。

关键约束:T: Send + 'static,任务的返回值必须可以在线程间传递。

TaskPool::spawn:单任务提交

如果不需要收集结果,直接用 spawn 提交一个 future:

rust
let pool = ComputeTaskPool::get();
let task = pool.spawn(async { 42 });
// task 是 Task<i32>,可以用 check_ready 轮询,或 .detach() 放弃结果

Task<T> 实现了 Future,可以 .await。如果不需要结果,调用 .detach() 让任务在后台完成。

三个池的选择

  • 需要当帧拿到结果 → ComputeTaskPool
  • 计算量大、可以多帧完成 → AsyncComputeTaskPool
  • 读文件、发网络请求 → IoTaskPool

选错池不会导致错误,但会影响调度优先级。ComputeTaskPool 的任务优先级最高,因为它假设你需要结果来推进当前帧。