10 个稳定版本

1.2.1 2024 年 1 月 18 日
1.2.0 2024 年 1 月 17 日
1.1.3 2023 年 12 月 16 日
1.0.3 2021 年 4 月 27 日
1.0.2 2021 年 3 月 31 日

#16WebAssembly

Download history 1007/week @ 2024-04-07 779/week @ 2024-04-14 1063/week @ 2024-04-21 764/week @ 2024-04-28 869/week @ 2024-05-05 1009/week @ 2024-05-12 369/week @ 2024-05-19 990/week @ 2024-05-26 1179/week @ 2024-06-02 1256/week @ 2024-06-09 1592/week @ 2024-06-16 1346/week @ 2024-06-23 622/week @ 2024-06-30 1475/week @ 2024-07-07 1466/week @ 2024-07-14 1296/week @ 2024-07-21

4,900 每月下载量
用于 5 crates

Apache-2.0

23KB
166 代码行

wasm-bindgen-rayon 是一个适配器,通过 WebAssembly (via wasm-bindgen, Web Workers 和 SharedArrayBuffer 支持) 在 Web 上启用基于 Rayon 的并发。

使用方法

在 Rust 中,WebAssembly 线程支持还不是一等公民,因此在使用此 crate 时有一些注意事项。请耐心等待 :)

要查看快速演示,请访问 https://rreverser.com/wasm-bindgen-rayon-demo/

注意事项

在我们开始之前,请查看 wasm-bindgen 线程文档 中列出的注意事项。虽然这个库专门针对 Rayon 并为你自动提供必要的垫片,但其中一些注意事项仍然适用。

设置

为了在 Web 上使用 SharedArrayBuffer,您需要启用 跨源隔离策略。请查看相关文章以获取详细信息。

然后,将 wasm-bindgenrayon 和此 crate 作为依赖项添加到您的 Cargo.toml

[dependencies]
wasm-bindgen = "0.2.74"
rayon = "1.8"
wasm-bindgen-rayon = "1.0"

然后,重新导出 init_thread_pool 函数

pub use wasm_bindgen_rayon::init_thread_pool;

// ...

这将在您库的最终生成的 JavaScript 中暴露一个异步的 initThreadPool 函数。

您需要在主线程上实例化模块后立即调用它,以便在调用实际库函数之前准备线程池

import init, { initThreadPool /* ... */ } from './pkg/index.js';

// Regular wasm-bindgen initialization.
await init();

// Thread pool initialization with the given number of threads
// (pass `navigator.hardwareConcurrency` if you want to use all cores).
await initThreadPool(navigator.hardwareConcurrency);

// ...now you can invoke any exported functions as you normally would

使用 Rayon

像平常一样使用 Rayon 迭代器,例如

#[wasm_bindgen]
pub fn sum(numbers: &[i32]) -> i32 {
    numbers.par_iter().sum()
}

将从 JavaScript 侧接受一个 Int32Array 并使用所有可用的线程计算其值的总和。

构建 Rust 代码

需要注意的第一个限制是,您必须使用 wasm-bindgen/wasm-packweb 目标(--target web)。

为什么?

这是因为 Wasm 代码需要将其自己的对象(WebAssembly.Module)在创建新线程时与它们共享。这个对象仅可以从 --target web--target no-modules 输出中访问,但因为我们还使用了 JS 片段功能,所以我们进一步将其限制为仅 --target web

另一个问题是,WebAssembly 目标的 Rust 标准库是在不支持线程的情况下构建的,以确保最大程度的可移植性。

由于我们希望标准 API(如 MutexArc)能够正常工作,因此您需要使用 nightly 编译器工具链,并传递一些标志来重新构建标准库,这包括您自己的代码。

为了减少破坏的风险,强烈建议使用固定的 nightly 版本。例如,撰写本文时最新的稳定 Rust 版本是 1.66,对应于 nightly-2022-12-12,它经过测试并且与这个包兼容。

使用配置文件

配置这些标志的最简单方法是

  1. 在您的项目目录中创建一个名为 rust-toolchain 的文件,并放入字符串 nightly-2022-12-12。这将告诉 Rustup 默认为您的项目使用 nightly 工具链。

  2. 在您的项目目录中的 .cargo/config.toml 文件中放入以下内容

    [target.wasm32-unknown-unknown]
    rustflags = ["-C", "target-feature=+atomics,+bulk-memory,+mutable-globals"]
    
    [unstable]
    build-std = ["panic_abort", "std"]
    

    这告诉 Cargo 重新构建支持 Wasm 原子操作的标准库。

然后,像往常一样使用 --target web 运行 wasm-pack

wasm-pack build --target web [...normal wasm-pack params...]

使用命令行参数

如果您不想默认配置这些参数,您可以将它们作为构建命令的一部分传递。

在这种情况下,整个命令如下所示

RUSTFLAGS='-C target-feature=+atomics,+bulk-memory,+mutable-globals' \
  rustup run nightly-2022-12-12 \
  wasm-pack build --target web [...] \
  -- -Z build-std=panic_abort,std

它看起来有点吓人,但它处理了所有事情 - 选择 nightly 工具链、启用所需的特性以及告诉 Cargo 重新构建标准库。您只需复制一次,并希望永远忘记它 :)

功能检测

并非所有浏览器 都支持 WebAssembly 线程,因此您可能需要构建两个版本 - 一个支持线程,另一个不支持 - 并在 JavaScript 侧使用功能检测来选择正确的版本。

您可以使用 wasm-feature-detect 库来实现此目的。代码大致如下

import { threads } from 'wasm-feature-detect';

let wasmPkg;

if (await threads()) {
  wasmPkg = await import('./pkg-with-threads/index.js');
  await wasmPkg.default();
  await wasmPkg.initThreadPool(navigator.hardwareConcurrency);
} else {
  wasmPkg = await import('./pkg-without-threads/index.js');
  await wasmPkg.default();
}

wasmPkg.nowCallAnyExportedFuncs();

与各种打包工具一起使用

WebAssembly 线程在底层使用 Web Workers 实例化具有相同 WebAssembly 模块 & 内存的其他线程。

wasm-bindgen-rayon 内部提供了所需的 JS 代码,并使用 在各种打包器中被识别的语法

与 Webpack 一起使用

如果您正在使用 Webpack v5(版本 >= 5.25.1),您不需要做任何特殊操作,因为它已经默认支持 打包 Workers

与 Parcel 一起使用

Parcel v2 也识别所使用的语法,并默认工作。

与 Rollup 一起使用

对于 Rollup,您需要 @surma/rollup-plugin-off-main-thread 插件(版本 >= 2.1.0),它提供了相同的功能,并已与这个包进行过测试。

或者,您可以使用内置必要插件的 Vite

不使用打包工具的使用

默认的JS胶水设计得非常好,可以与打包器和代码拆分配合使用,但遗憾的是,由于对导入路径的处理不同,在浏览器中表现不佳(参见 WICG/import-maps#244)。

如果您想在没有打包器的情况下构建此库,请在您的 Cargo.toml 中启用 wasm-bindgen-rayonno-bundler 功能。

wasm-bindgen-rayon = { version = "1.0", features = ["no-bundler"] }

许可证

此软件包采用 Apache-2.0 许可。

依赖项

~2.4–4.5MB
~81K SLoC