chemicstry / wasm_thread

A rust `std::thread` replacement for wasm32 target
Apache License 2.0
123 stars 16 forks source link

Add support for --target web and spawning threads from other spawned threads #5

Closed DouglasDwyer closed 2 years ago

DouglasDwyer commented 2 years ago

I needed this functionality for a personal project, so I went ahead and added it. I just thought that I might share it here, in case it could prove useful to anyone else.

First, this PR adds support for compiling with wasm-pack to the web target with ES Modules. This is hidden behind the feature flag es_modules, and is accomplished by providing a polyfill for situations where modules in workers still aren't supported. To build the crate with --target web, one simply enables the feature. With the feature off (which is the default) the crate targets no-modules.

Next, this PR fixes the inability to spawn worker threads from other worker threads on modern browsers. This is accomplished by posting a message back to the main thread whenever a new worker should be spawned, and allowing the main thread to handle all spawn requests.

These changes have been tested and work correctly on the latest versions of Chrome, Edge, and Firefox.

Please let me know if there are any questions I can answer, or anything you'd like to change about this PR. I think these changes might be helpful to consumers of this crate in the future.

chemicstry commented 2 years ago

Hey, thanks for the PR!

I kind of deprecated this library, because https://github.com/GoogleChromeLabs/wasm-bindgen-rayon supersedes it (also see #4). However, if there are cases where the rayon lib is not suitable, I could release a new version of this crate with your PR. In that case, could you update README and add an example of how to use it with wasm-pack?

DouglasDwyer commented 2 years ago

Certainly - I've gone ahead and updated the README and added a wasm-pack example for both web and no-modules. Unfortunately, the example needs to be its own Cargo package, because wasm-pack does not support building examples. Let me know if there is anything else you'd like to change, or feel free to add additional commits.

Thanks for offering to accept this PR. In my opinion, it just makes sense to have a replacement for std::thread available. Rayon is a nice abstraction, useful in many cases, but sometimes it's more helpful to be able to spawn threads and manage their lifetimes yourself. Besides, with a fully-working threads replacement for WASM, it seems to me that the wasm-bindgen-rayon crate is unnecessary anyway; it's possible to simply use normal Rayon. This gives one the additional flexibility to create and destroy threadpools on demand.

EDIT: I just noticed that Firefox drops any spawned threads after ~7 seconds because references to the workers are not retained. I will make another commit Thursday to fix this by retaining worker handles in the main Rust thread.

DouglasDwyer commented 2 years ago

Hi, I've gone ahead and also fixed the bug where Firefox garbage collects long-lived workers because references to them are not retained. In the process, I was also able to remove some unsafe code and make things cleaner. Let me know if there's anything else - changes have been tested in Firefox, Chrome, and Edge. They should be ready to merge.

chemicstry commented 2 years ago

Thanks for the work! I will clean it up a little and release a new version

felipellrocha commented 2 years ago

@DouglasDwyer Curious, how did you get rayon itself to run without wasm-bindgen-rayon?

DouglasDwyer commented 2 years ago

Hi @felipellrocha - I haven't actually tried it, that was a hypothetical example. It should, however, be theoretically possible by using a custom ThreadPoolBuilder and the spawn_handler method. You could use this to replace Rayon's normal threadpool spawning with wasm_thread, and I imagine it should work. There might, however, be some problems - if Rayon at some point blocks on the main thread with this technique, then that could cause a deadlock (I somewhat doubt this because wasm-bindgen-rayon uses normal Rayon too; it is just a custom shim). Feel free to let me know if it doesn't work and we can look into it!