编程 libsodium WebAssembly 基准 2024→2026:9 个运行时,wide_arithmetic 把 Wasmtime 从 2.41x 拉到 1.46x

2026-10-02 00:04:20

libsodium WebAssembly 基准 2024→2026:9 个运行时,wide_arithmetic 把 Wasmtime 从 2.41x 拉到 1.46x

信源:WebAssembly runtimes performance in 2026(前作:2019、2021、2023)

各运行时发布页:

要回答的问题很具体:同一份 C 加密代码编译成 WebAssembly,在最新运行时、一年前运行时、两年前运行时上跑,性能是不是真的提升了。不是看某个微基准能不能打败原生,也不是比谁的图好看。

结论先放这儿:

  • WAVM 和 WasmEdge 可以非常快。WasmEdge 0.17.0 必须显式指定 --run-mode=aot,否则编译后的模块会按解释器模式运行。
  • WAMR 的 AOT 模式也很快,与 WAVM 和最好的 Wasmtime 结果并列。
  • wasm2c、Wasmer、Wasmtime 都足够接近原生,对 CPU 密集型加密任务有吸引力。
  • Wazero 慢,但稳定。
  • Node 和 Bun 那几行需要重跑更长的基准循环——短循环没能充分预热 JIT。
  • 实验性的 WebAssembly wide_arithmetic 指令对支持它的运行时意义重大。

测什么

测试程序是 libsodium 的基准套件,基于提交 8e3be8615ba6adcd7babaecf5e76f516890ba5fb 构建。

构建了原生基线和几个 WebAssembly 变体:

  • 原生 x86-64,用 Zig 以本地 CPU 为目标编译
  • 普通 WebAssembly
  • 带 lime1 的 WebAssembly
  • 带 lime1 和 simd128 的 WebAssembly
  • 带 lime1、simd128 和 wide_arithmetic 的 WebAssembly

原生参考用 -Dcpu=native 构建。wasm2c 生成的 C 代码用 zig cc -O3 -march=native 编译。

WAMR 走 AOT 模式:wamrc 把每个 .wasm 编成 .aot,再由 iwasm 运行。wamrc 不接受 --cpu=native,所以用 --target=x86_64 --cpu=x86-64-v4 --opt-level=3,与主机的可用 x86-64 功能级别匹配,在能编译这些模块的 WAMR 版本上都能工作。

原生命令:

zig build -Denable_benchmarks -Doptimize=ReleaseFast -Dcpu=native -Diterations=3

WebAssembly 命令形式相同,换成 wasm32-wasi 目标和对应的 CPU 字符串:

zig build -Denable_benchmarks -Dtarget=wasm32-wasi -Doptimize=ReleaseFast -Diterations=3
zig build -Denable_benchmarks -Dtarget=wasm32-wasi -Doptimize=ReleaseFast -Dcpu=lime1 -Diterations=3
zig build -Denable_benchmarks -Dtarget=wasm32-wasi -Doptimize=ReleaseFast -Dcpu=lime1+simd128 -Diterations=3
zig build -Denable_benchmarks -Dtarget=wasm32-wasi -Doptimize=ReleaseFast -Dcpu=lime1+simd128+wide_arithmetic -Diterations=3

主机是 AMD Ryzen AI 9 HX 470,12 核 24 线程。CPU 睿频已禁用,最大频率 2 GHz。系统 Linux 7.1.0-rc7,Zig 0.17.0-dev.948+e949341b7。

下面的数字是每个基准相对于原生构建的几何平均减速比,越低越好。2.0 表示“在这台机器上比原生慢两倍”。ITERATIONS=3 意味着 libsodium 那些极小的测试会有噪声和量化效应;报告时间为零的行已从聚合中剔除。进程没有绑核。用来比较运行时的大致行为没问题,最后一位小数不必当真。

版本矩阵

除 WAVM 外,所有运行时都取了 2026 年 6 月 23 日可用的最新稳定版,以及大约一年前和两年前的稳定版。

Runtime202420252026
Bun1.1.161.2.171.3.14
Node22.3.024.2.026.3.1
WAMR2.1.02.3.12.4.4
WABT wasm2c1.0.351.0.371.0.41
WasmEdge0.14.00.14.10.17.0
Wasmer4.3.26.0.17.1.0
Wasmtime22.0.034.0.046.0.0
WAVMn/an/anightly/2026-04-05
Wazero1.7.31.9.01.12.0

WAVM 的历史对比有点麻烦:旧的可用 nightly 对 2024 和 2025 两个时间段都退化成了 2022 年的二进制,而这个二进制拒绝在这台机器上运行。只保留 2026 年的 nightly。

WAMR 2.1.0(选定的 2024 版本)能装,但它的 AOT 编译器在这些 Zig 生成的模块上失败,报 invalid WASM stack data type。版本留在矩阵里,聚合结果不含它。

基准 WebAssembly(无特性)

普通 WebAssembly 构建,没有 lime1、SIMD 或 wide arithmetic。

Runtime202420252026
WAVMn/an/a1.41
WAMR AOTn/a1.591.57
WasmEdge1.661.981.74
wasm2c2.012.081.86
Wasmer2.132.562.08
Wasmtime2.672.542.41
Wazero4.844.704.72
Node8.608.227.95
Bun27.4126.428.77

没有普遍趋势。

Wasmtime 稳步提升:2.67 → 2.54 → 2.41 倍原生。不算革命,但确实在进步。Node 也在缓慢提升,8.60 → 7.95。Wazero 基本持平:4.84 / 4.70 / 4.72。WAMR 的 AOT 模式 2025 年就已经很快,2026 年稍快:1.59 → 1.57。Wasmer 在 2025 版本上退步,2026 年恢复。wasm2c 在 2026 年有适度提升——如果提前把 WebAssembly 翻译成原生 C 符合部署模型,它仍然是最佳选择之一。

Bun 是异常值:2024 和 2025 的结果远远落后,2026 年比 2025 年快约三倍,但仍比 Node 慢,方向是好的。

WasmEdge 也快,但它的命令行行为变化足够大。第一次跑 0.17.0 时不小心让编译后的模块走了解释器模式,结果异常慢。加上 --run-mode=aot 后恢复正常:2026 年 1.74 倍原生,介于 2024 和 2025 的结果之间。

按年份的最佳支持构建

上面的表处处比较同一个 WebAssembly 目标,便于横向对照。真要为自己的部署选运行时,更关心的是该运行时实际能跑的最快构建。

所以对每个运行时和年份,还从支持的构建里挑出最好的完整结果:baseline、lime1、lime1+simd128、lime1+simd128+wide_arithmetic。

Runtime2024 best2025 best2026 best
WAVMn/an/a1.41 (baseline)
WAMR AOTn/a1.42 (lime1+simd128)1.42 (lime1+simd128)
WasmEdge1.62 (lime1+simd128)1.64 (lime1)1.64 (lime1)
wasm2c2.01 (baseline)2.08 (baseline)1.86 (baseline)
Wasmer2.09 (lime1)2.49 (lime1)1.33 (lime1+simd128+wide_arithmetic)
Wasmtime2.60 (lime1+simd128)1.52 (lime1+simd128+wide_arithmetic)1.46 (lime1+simd128+wide_arithmetic)
Wazero4.84 (baseline)4.64 (lime1)4.71 (lime1+simd128)
Node8.60 (baseline)7.99 (lime1)7.95 (baseline)
Bun27.35 (lime1)26.23 (lime1)8.77 (baseline)

按最佳支持构建排序,2026 年排名:

  1. Wasmer (lime1+simd128+wide_arithmetic) 1.33
  2. WAVM (baseline) 1.41
  3. WAMR AOT (lime1+simd128) 1.42
  4. Wasmtime (lime1+simd128+wide_arithmetic) 1.46
  5. WasmEdge (lime1) 1.64
  6. wasm2c (baseline) 1.86
  7. Wazero (lime1+simd128) 4.71
  8. Node (baseline) 7.95
  9. Bun (baseline) 8.77

CPU 特性变体

WebAssembly 特性的故事比运行时年份的故事更有意思。2026 年版本的聚合减速:

Runtimebaselinelime1lime1+simd128lime1+simd128+wide_arithmetic
WAVM1.411.591.43unsupported
WAMR AOT1.571.441.42unsupported
WasmEdge1.741.641.76unsupported
Wasmer2.082.022.031.33
Wasmtime2.412.302.371.46
Wazero4.724.774.71unsupported
Node7.958.058.25unsupported
Bun8.7711.059.53unsupported

lime1 和 simd128 单独用都不是魔法。有时有用,有时有害,有时差异被基准噪声淹没。

wide_arithmetic 不一样。在完整测试的稳定版里,只有 Wasmtime 和 Wasmer 能跑完整的 wide_arithmetic 构建;WAMR 以不支持的操作码 0xfc13 拒绝。而当它生效时,是整个实验里最大的加速:

  • Wasmtime 46.0.0:不用该特性 2.41 倍原生,用后 1.46 倍原生。
  • Wasmer 7.1.0:不使用时 2.08 倍原生,用后 1.33 倍原生。

这正是加密代码需要的改变。libsodium 里很多昂贵操作是算术密集型的,如果 WebAssembly ISA 能直接表达这些算术,运行时需要重新发现 C 编译器早已知道的东西就少得多。

失败案例

大多数运行顺利完成,但不是全部。

Bun 1.2.17 在 baseline 构建的 box_easy 上失败。Bun 1.1.16 在 lime1 和 lime1+simd128 构建的 pwhash_argon2i 上失败。Node 22.3.0 在 baseline、lime1 和 lime1+simd128 构建的 pwhash_argon2i、pwhash_argon2id、pwhash_scrypt 上失败。

Node 22.3.0 的密码哈希失败没法通过调大 Node 的 JavaScript 堆或栈设置解决,而是通过给 Wasm 模块显式的最大线性内存解决的。baseline 构建下,1024 页(64 MiB)的最大值让 pwhash_argon2i、pwhash_argon2id 和 pwhash_scrypt 跑完;pwhash_scrypt 在 512 页失败,在 1536 页及以上又段错误。这看起来是 V8 内存模式的阈值,而不是简单的“内存给多就好”。

WAMR 2.1.0(2024 版本)即使在 AOT 模式下也无法编译 baseline 模块。WAMR 2.3.1 和 2.4.4 能编译并运行 baseline、lime1、lime1+simd128,但跑不了 wide_arithmetic。

这些失败已从聚合中排除;报告的中位时间为零的行同样排除。

运行时在变快吗

一部分在变快。

Wasmtime 是最明确的“是”:在这个基准里逐年变快,幅度不大但持续。Node 也是“是”,只是斜率平缓。Bun 在 2025 到 2026 之间是响亮的“是”。Wazero 基本持平。WAMR 在能工作的版本之间也基本持平,但“持平”在约 1.4 到 1.6 倍原生已经是非常好的位置。Wasmer 只看 baseline 表现不一,但 2026 版本支持 wide_arithmetic 改变了加密代码的实际答案——开启该特性后,它是我能比较的当前正常版本里最快的完整 2026 结果。wasm2c 依然很好。WAVM 给出了最快的 2026 baseline 数字,但没有公平的 2024/2025 对照。WasmEdge 一旦强制走 AOT 模式,表现依然出色。

要点

在 WebAssembly 里跑 CPU 密集型加密任务,运行时选择仍然很重要。最快和最慢的当前结果差距很大:Wasmer 配 wide_arithmetic 是 1.33 倍原生,当前 Bun baseline 是 8.77 倍原生。

特性支持同样重要。当 WebAssembly 模块能用上更好的算术指令,同一个运行时可以从“还不错”变成“惊人地接近原生”。

令人欣慰的是主流运行时没有停滞:Wasmtime 稳步提升,Bun 大幅跃升,Wasmer 拿到了对真实加密工作负载很关键的特性。

不太令人欣慰的是 WebAssembly 性能仍然不是单一概念。它取决于运行时、版本、启用的 WebAssembly 特性、代码是否经 JavaScript 的 WASI 跑,以及是否允许提前原生编译。

所以,对自己实际的工作负载做基准测试。如果负载类似 libsodium,2026 年的答案大致是:WebAssembly 可以接近原生,wide_arithmetic 值得关注,而且确实有一些运行时在变快。

推荐文章

程序员茄子在线接单