Skip to content

single_threaded_task_pool scope api doesn't work in wasm #1924

Open
@mockersf

Description

Bevy version

0.5 and d119c1ce14da59089a65373d59715a41d05251ad

Operating system & version

Firefox & Chromium

What you did

Trying to use the task pool to execute several tasks, I hoped to have the same code running in both wasm and native

use bevy::{prelude::*, tasks::prelude::*};

fn main() {
    let mut builder = App::build();
    builder.add_plugins(DefaultPlugins);

    let asset_io = bevy::asset::create_platform_default_asset_io(&mut builder);

    builder
        .insert_resource(asset_io)
        .init_resource::<Vec<String>>()
        .add_startup_system(get_from_future.system())
        .add_system(log_stuff.system())
        .run();
}

fn get_from_future(
    task_pool: Res<ComputeTaskPool>,
    mut expensive_to_get: ResMut<Vec<String>>,
    asset_io: Res<Box<dyn bevy::asset::AssetIo>>,
) {
    let asset_io = &*asset_io;
    *expensive_to_get = task_pool
        .scope(|scope| {
            for i in 0..3 {
                scope.spawn(async move {
                    std::str::from_utf8(
                        &asset_io
                            .load_path(&std::path::Path::new(&format!("file_{}.big", i)))
                            .await
                            .unwrap(),
                    )
                    .unwrap()
                    .to_string()
                });
            }
        })
        .into_iter()
        .collect();
}

fn log_stuff(expensive_to_get: Res<Vec<String>>) {
    bevy::log::warn!("got {:?}", *expensive_to_get);
}

This works on native!

Building this for wasm32 gives an error:

26 |                 scope.spawn(async move {
   |                       ^^^^^ future created by async block is not `Send`

Indeed, spawn requires the future to be Send in the single_threaded_task_pool. This could probably be removed anyway as it calls spawn_local which doesn't need Send

pub fn spawn<Fut: Future<Output = T> + 'scope + Send>(&mut self, f: Fut) {
self.spawn_local(f);
}

Let's try to run this with spawn_local to check if it would work better.At least it compiles that way!

And crash in the browser

test.js:276 panicked at 'assertion failed: `(left == right)`
  left: `true`,
 right: `false`: cannot recursively acquire mutex',

And rightly so. In the scope function:

scope
.results
.iter()
.map(|result| result.lock().unwrap().take().unwrap())
.collect()

The lock() is on a mutex, and that can't work because you can't block in wasm...

Using the task pool in wasm will work for trivial task that aren't long enough to lock the mutex, but will fail for any real case...

I tried a few things but couldn't get it to work

Metadata

Assignees

No one assigned

    Labels

    A-AppBevy apps and pluginsC-BugAn unexpected or incorrect behaviorO-WebSpecific to web (WASM) builds

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions