4个版本
0.2.0 | 2022年3月23日 |
---|---|
0.1.2 | 2021年9月10日 |
0.1.1 | 2021年9月10日 |
0.1.0 | 2021年9月8日 |
#368 在 WebAssembly 中
在 2 crate 中使用
20KB
197 行
wasm-futures-executor
这个crate提供了一个与futures_executor::ThreadPool
相同的API的异步任务执行器,针对Web浏览器环境。不是通过std::thread
创建线程,而是创建web workers。这个crate努力使这个过程尽可能无缝和容易。
示例用法
use futures::channel::mpsc;
use futures::StreamExt;
use js_sys::Promise;
use wasm_bindgen::prelude::*;
use wasm_futures_executor::ThreadPool;
#[wasm_bindgen]
pub async fn start() -> Result<JsValue, JsValue> {
let pool = ThreadPool::max_threads().await?;
let (tx, mut rx) = mpsc::channel(10);
for i in 0..20 {
let mut tx_c = tx.clone();
pool.spawn_ok(async move {
tx_c.start_send(i * i).unwrap();
});
}
drop(tx);
let mut i = 0;
while let Some(x) = rx.next().await {
i += x;
}
Ok(i.into())
}
.. 使用它
import init, { start } from './sample.js';
async function run() {
await init();
const res = await start();
console.log("result", res);
}
run();
使用以下命令构建你的项目
RUSTFLAGS='-C target-feature=+atomics,+bulk-memory,+mutable-globals' \
cargo +nightly build --target wasm32-unknown-unknown --release -Z build-std=std,panic_abort
wasm-bindgen \
./target/wasm32-unknown-unknown/release/sample.wasm \
--out-dir . \
--target web \
--weak-refs
.. 或者如果你想要使用wasm-pack build -t web
,请确保设置夜间工具链和正确的RUSTFLAGS
(例如,通过创建rust-toolchain.toml
和.cargo/config
文件,就像这个仓库中那样)。
请查看示例,其中包含一个完整的端到端示例项目,不使用打包器,以及使用Webpack 5的示例-webpack。
注意:这个crate需要使用web
目标的wasm-bindgen/
wasm-pack
。鉴于ES模块的广泛标准化,这应该大部分没问题。
工作原理
类似于futures-executor
提供的异步执行器,在ThreadPool
实例化时,会启动多个worker "线程"。每个线程都是一个web worker,它加载一些js粘合代码。粘合代码作为js片段提供,该片段从wasm-bindgen生成的js粘合代码中链接。这样,它对任何打包器都是透明的。每个web worker使用以下参数构造
- WebAssembly模块初始化及其共享内存(《
SharedArrayBuffer
》)。 - 第三个是一个指向某些共享状态的指针,包括一个通道,异步任务通过该通道传递。为此,库提供了
worker_entry_point
函数。
一旦 ThreadPool
被丢弃,所有通道都将关闭,并且 Web 工作线程将被终止。
遗憾的是,这需要每晚的编译器,因为 Rust 的标准库需要重新编译以包含以下不稳定功能
atomics
:(Rust 功能)支持 wasm 原子操作,请参阅 https://github.com/rust-lang/rust/issues/77839bulk-memory
:(LLVM 功能)生成原子指令、共享内存、被动段等。mutable-globals
:(LLVM 功能)
注意:当工作线程被销毁时,可能会泄漏一些内存(例如线程局部存储或线程的栈)。我建议向 --weak-ref
选项传递 wasm-bindgen
,以便让 wasm-bindgen 根据以下 WeakRef 建议创建用户定义的终结器。
总的来说,在 Rust 中实现 wasm 线程似乎失去了一些势头 ..
浏览器支持
通过 SharedArrayBuffer
共享内存很快(从 Chrome 92 开始)将需要设置正确的标头以标记网站为“跨源隔离”,这意味着需要与主文档一起发送以下标头
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
更多信息请参阅 此链接。
在 Web 工作线程中加载模块目前仅在 Chromium 中受支持。Firefox 似乎终于取得了一些 进展。作为一种解决方案,您可以包含一个 workers-polyfill。
如果您针对的是旧版浏览器,您可能需要进行一些功能检测,并且优雅地回退--但这超出了本文档的范围。
这值得吗?
在线程边界发送和生成未来存在明显的开销。这对于长期任务来说最有意义(例如,查看 阶乘 演示,性能提升了大约 3 倍)。像往常一样,请确保对您的用例进行性能分析。
相关包和更多信息
-
最重要的资源是 wasm-bindgen 文档 中出色的光线追踪演示及其背景 博客文章。
-
wasm-bindgen-rayon 包提供了广泛的文档和良好的端到端示例。
-
wasm_thread 包在方法上与本包非常相似。主要区别在于使用了 ES 模块。
许可证
根据您选择的以下许可证之一
- Apache 许可证 2.0(《LICENSE-APACHE》或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证(《LICENSE-MIT》或 http://opensource.org/licenses/MIT)
供您选择。
贡献
除非您明确声明,否则您提交的任何有意包含在本作品中的贡献(根据 Apache-2.0 许可证定义),都将根据上述许可进行双重许可,而无需任何其他条款或条件。
依赖项
~9–18MB
~242K SLoC