Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
wasm-mt
A multithreading library for Rust and WebAssembly.
wasm-mt
helps you create and execute Web Worker based threads. You can program the threads simply using Rust closures and orchestrate them with async/await
.
Thanks:
- wasm-bindgen developers
- @alecmocatta for the serde_traitobject crate
Getting started
Requirements:
- rustc (nightly)
wasm-pack build
with the--target no-modules
option
Cargo.toml:
wasm-mt = "0.1"
serde = { version = "1.0", features = ["derive"] }
serde_closure = "0.2"
Creating a thread
First, create a [WasmMt
] thread builder with [new
][WasmMt::new] and initialize it:
use wasm_mt::prelude::*;
let pkg_js = "./pkg/exec.js"; // path to `wasm-bindgen`'s JS binding
let mt = WasmMt::new(pkg_js).and_init().await.unwrap();
Then, create a [wasm_mt::Thread
][Thread] with the [thread
][WasmMt::thread] function and initialize it:
let th = mt.thread().and_init().await.unwrap();
Executing a thread
Using the [exec!
] macro, you can execute a closure in the thread and await
the result:
// fn add(a: i32, b: i32) -> i32 { a + b }
let a = 1;
let b = 2;
let ans = exec!(th, move || {
let c = add(a, b);
Ok(JsValue::from(c))
}).await?;
assert_eq!(ans, JsValue::from(3));
You can also execute an async closure with exec!
:
// use wasm_mt::utils::sleep;
// async fn sub(a: i32, b: i32) -> i32 {
// sleep(1000).await;
// a - b
// }
let a = 1;
let b = 2;
let ans = exec!(th, async move || {
let c = sub(a, b).await;
Ok(JsValue::from(c))
}).await?;
assert_eq!(ans, JsValue::from(-1));
Executing JavaScript in a thread
Using the [exec_js!
] macro, you can execute JavaScript within a thread:
let ans = exec_js!(th, "
const add = (a, b) => a + b;
return add(1, 2);
").await?;
assert_eq!(ans, JsValue::from(3));
Similarly, use [exec_js_async!
] for running asynchronous JavaScript:
let ans = exec_js_async!(th, "
const sub = (a, b) => new Promise(resolve => {
setTimeout(() => resolve(a - b), 1000);
});
return await sub(1, 2);
").await?;
assert_eq!(ans, JsValue::from(-1));
Making executors
By using [wasm_mt:Thread
][Thread], you can easily create custom executors. One such example is the wasm-mt-pool
crate. It provides a thread pool that is based on the work stealing scheduling strategy.
Here, for simplicity, we show the implementation of much more straightforward executors: a serial executor and a parallel executor.
First, prepare a Vec<wasm_mt::Thread>
containing initialized threads:
let mut v: Vec<wasm_mt::Thread> = vec![];
for i in 0..4 {
let th = mt.thread().and_init().await?;
v.push(th);
}
Then, here's the executors in action. Note, in the latter case, we are using wasm_bindgen_futures::spawn_local
to dispatch the threads in parallel.
console_ln!("🔥 serial executor:");
for th in &v {
console_ln!("starting a thread");
let ans = exec!(th, move || Ok(JsValue::from(42))).await?;
console_ln!("ans: {:?}", ans);
}
console_ln!("🔥 parallel executor:");
for th in v {
spawn_local(async move {
console_ln!("starting a thread");
let ans = exec!(th, move || Ok(JsValue::from(42))).await.unwrap();
console_ln!("ans: {:?}", ans);
});
}
Observe the starting/ending timing of each thread in the developer console:
🔥 serial executor:
starting a thread
ans: JsValue(42)
starting a thread
ans: JsValue(42)
starting a thread
ans: JsValue(42)
starting a thread
ans: JsValue(42)
🔥 parallel executor:
(4) starting a thread
(4) ans: JsValue(42)