龙空技术网

万字长文!2023 年 WebAssembly 各个运行时性能对比!

高级前端进阶 6653

前言:

当前我们对“ubuntu文本搜索gra”都比较重视,我们都想要了解一些“ubuntu文本搜索gra”的相关文章。那么小编同时在网络上搜集了一些关于“ubuntu文本搜索gra””的相关文章,希望朋友们能喜欢,姐妹们一起来学习一下吧!

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

高级前端进阶

前言

本文主要和大家介绍在 2023 年各个 WebAssembly 运行时的性能比较,同时让大家更好、更深入了解每个 WebAssembly 运行时。在年初,我也确实使用 WebAssembly 将客户端应用成功移植到了 Web,这也是为什么我一直对 WebAssembly 充满好奇的原因。我甚至在头条上开了一个合集来专门探讨 WebAssembly ,并将持续关注 WebAssembly 最新动态。

图片来自:

以前我也单独撰写过一篇文章《2023 年让 WebAssembly 大火的 10+应用!》来探讨 WebAssembly 在前端的应用。正如大家所看到的,当我们还在迟疑是否要在日常开发中引入 WebAssembly 的时候,很多优秀的应用、工具已经开始吃 WebAssembly 的红利了,而且取得了不错的成就,这可能也是为什么浏览器厂商、开发者如此热衷 WebAssembly 的原因。

本文主要内容来自 Frank Denis 编写的《Performance of WebAssembly runtimes in 2023》,文章链接已经在文末给出,但是“高级前端进阶”对部分内容进行自组织、加工,从而能够更好的读懂它。

1.WebAssembly 各个优秀生态成员介绍

虽然,WebAssembly 在浏览器中已经出现了很长一段时间,比如 :Chrome>57、Edge>16、Safari>11、FireFox>52、Opera>44 等浏览器都已经原生支持 WebAssembly,但是国内前端开发似乎对这方面没有太大的体感。因此,为了更好的读懂下面的文章内容,需要先带着大家一起熟悉 WebAssembly 生态中优秀的成员。

1.1 LLVM

LLVM 是一个用于构建高度优化的编译器(compilers)、优化器(optimizers)和运行时(run-time environments)环境的工具包。

图片来自:

LLVM 项目有多个组件, 该项目的核心本身就是“LLVM”。 这包含处理中间表示并将它们转换为目标文件所需的所有工具、库和头文件。 工具包括:汇编器、反汇编器、位码分析器和位码优化器。

类 C 语言使用 Clang 前端。 该组件使用 LLVM 将 C、C++、Objective-C 和 Objective-C++ 代码编译成 LLVM 位码,并从那里编译成目标文件。其他组件包括:libc++ C++ 标准库、LLD 链接器等。

目前 LLVM 在 Github 上有 18.8K 的 star、7.1k 的 fork、2800+的代码贡献者。

1.2 Emscripten

Emscripten 使用 LLVM 和 Binaryen 将 C 和 C++ 编译成 WebAssembly, Emscripten 的输出可以在 Web、Node.js 和 wasm 运行时中运行。

Emscripten 为 OpenGL 和 SDL2 等流行的可移植 API 提供 Web 支持,允许移植复杂的图形原生应用程序,例如 Unity 游戏引擎和 Google Earth,它可能也可以移植代码库!

虽然 Emscripten 主要专注于使用 Clang 编译 C 和 C++,但它可以与其他使用 LLVM 的编译器集成。例如,Rust 具有 Emscripten 集成,具有 wasm32-unknown-emscripten 和 asmjs-unknown-emscripten 目标。

目前 Emscripten 在 Github 上有 23.5K 的 star、3k 的 fork、700+的代码贡献者。

1.3 WASI

WASI,全名为 WebAssembly System Interface。我们知道,WebAssembly 是一种新的字节码格式,目前被应用于 web 中,由于其可移植、体积小,安全性的等优点被渐渐广泛认可,但是其主要是运行在浏览器中。

一些开发者想让 WebAssembly 也可以运行在非浏览器环境中,这就产生了 WASI。

WASI 是一个新的 API 体系, 由 Wasmtime 项目设计, 目的是为 WASM 设计一套引擎无关(engine-indepent)、面向非 Web 系统(non-Web system-oriented)的 API 标准。

1.4 libsodium

Sodium 是全新的、易于使用的软件库,用于加密、解密、签名、密码散列等等场景(在文章后面能看到)。它是 NaCl 的可移植、可交叉编译、可安装、可打包的分支,具有兼容的 API 和可进一步提高可用性的扩展 API。

它的目标是提供构建更高级别加密工具所需的所有核心操作。Sodium 支持多种编译器和操作系统,包括 Windows(使用 MingW 或 Visual Studio、x86 和 x64)、iOS、Android,以及 Javascript 和 Webassembly 等。

目前 Sodium 在 Github 上有 10.8K 的 star、1.7k 的 fork、100+的代码贡献者。

1.5 binaryen

Binaryen 是 WebAssembly 的编译器和工具链基础设施库,用 C++ 编写。 它旨在使编译为 WebAssembly 变得简单、快速和有效。binaryen 具有以下明显特点:

简单:Binaryen 在单个标头中有一个简单的 C API,也可以从 JavaScript 使用。 它接受类似 WebAssembly 形式的输入,但也为喜欢它的编译器接受通用控制流图。快速:Binaryen 的内部 IR 使用紧凑的数据结构,专为完全并行的代码生成和优化而设计,使用所有可用的 CPU 内核。 Binaryen 的 IR 也非常容易和快速地编译成 WebAssembly,因为它本质上是 WebAssembly 的一个子集。有效:Binaryen 的优化器可以改善代码大小和速度。 这些优化旨在使 Binaryen 足够强大,可以单独用作编译器后端。

目前 binaryen 在 Github 上有 6.3K 的 star、600+ 的 fork、140+的代码贡献者。

1.6 wasmedge

WasmEdge 是一种轻量级、高性能且可扩展的 WebAssembly 运行时,由 C++编写,适用于云原生、边缘和去中心化应用程序。 它为无服务器应用程序、嵌入式功能、微服务、智能合约和物联网设备提供支持。

目前 WasmEdge 在 Github 上有 5.6K 的 star、500+ 的 fork、130+的代码贡献者。

1.7 Wasmer

Wasmer 是一种快速且安全的 WebAssembly 运行时,它使超轻量级容器可以在任何地方运行:从桌面到云、边缘和物联网设备。目前 Wasmer 在 Github 上有 14.7K 的 star、630+ 的 fork、5k 的项目使用它,140+的代码贡献者。

1.8 cranelift

Cranelift(以前称为 Cretonne)由 Bytecode Alliance 开发维护,是一个优化编译器后端,可将与目标无关的中间表示转换为可执行机器代码。 它是用 Rust 编写的。 该项目于 2016 年启动,目前由字节码联盟开发。与 LLVM 等更侧重于提前编译的编译器后端不同,Cranelift 侧重于即时编译,短编译时间是该项目的明确目标。

截至 2023 年,Cranelift 支持多种指令集架构,例如: x86-64、AArch64、RISC-V 和 IBM z/Architecture 等。目前 cranelift 在 Github 上有 2.5K 的 star、200+ 的 fork、110+的代码贡献者。

1.9 其他术语wasm32-wasi:Rust 编程语言支持将 WebAssembly 作为编译目标, 编译为 WebAssembly 涉及通过 --target 标志指定目标,在 Rust 中有许多用于 WebAssembly 编译的“目标三元组”。而 wasm32-wasi 就是其中之一,使用 wasmtime 的时候需要。 WASI 目标已集成到标准库中,旨在生成独立的二进制文件。多通道编译器:多通道编译器多次处理程序的源代码或语法树,将一个大程序分成多个小程序进行处理。它开发了多个中间代码,所有这些多通道都将前一阶段的输出作为输入,所以它需要更少的内存。2.libsodium 对 WebAssembly 的支持

从 2013 年以来,在 Emscripten 项目的帮助下,使得在 Web 浏览器中使用 libsodium 成为可能。从那时起,Web 浏览器引入了 WebAssembly,从而使得运行最初不是用 JavaScript 编写的代码成为可能。

libsodium 在 2017 年增加了对 WebAssembly 的一流支持,在支持它的 Web 浏览器和上下文中带来了明显的速度提升,从而使得相同的代码可以在多个平台上无缝迁移、运行。

图片来自:

与 JavaScript 一样,很多应用程序也逐渐在服务器端使用 WebAssembly。 WebAssembly 允许忽略运行时实现中的错误,同时不允许不受信任的代码在沙箱之外读取或写入内存。 这些特性使 WebAssembly 成为应用程序插件、函数即服务(Function-as-a-service )、智能合约等场景的不二选择。

2019 年,libsodium 添加了对新 WebAssembly 目标 (wasm32-wasi) 的支持,即使没有 JavaScript 引擎,也可以在 Web 浏览器之外使用该库。目前为止,很多运行时都已经支持 wasm32-wasi,但在同一平台上,即使相同的代码也会有不同的运行时性能表现。因此,libsodium 目前已经将 wasm32-wasi 的基准测试功能做了集成。

事实证明,该基准比微基准(micro-benchmarks)更能代表现实世界的性能。 当然,libsodium 是一个加密库。 但是被测量的原语(primitives)的多样性运用了 WebAssembly 运行时、编译器、JIT 实现(或未实现)的绝大多数优化,这个基准也逐渐被证明,成为真实世界应用程序的一个很好的代表。

自推出以来,libsodium 基准已经被不同的角色广泛采用,比如:

运行时开发者:改进运行时优化管道研究人员:用于衡量实验对 WebAssembly 的影响用户:用于选择最佳运行时3.自上次基准测试以来WebAssembly发生了什么InNative 仍在积极维护,但仍未获得 WASI 支持, 虽然它看起来值得进行基准测试,但不幸的是,这暂时仍然是一个阻碍。Lucet 已经停产,因为 Wasmtime 和 Wasmer 使用相同的代码生成器提供相同功能。Fizzy 似乎不再被维护。WAVM 似乎也不再维护。以往 WAVM 在实施提案上总是快一步,并且一直是最快的运行时。 EPIC Games 放弃 WebAssembly 了吗? FAASM 使用的分支不断进行小更新,但上游存储库中没有更多输出。 这对 WebAssembly 社区来说是一个巨大的损失。SSVM 变成了 WasmEdge,来自 Cloud Native Computing Foundation 的运行时。 该项目非常活跃,从第一天起就专注于性能。 它具有很多功能,包括运行插件的能力。Wasm3 的发展已经放缓。 然而,它仍然是唯一可以轻松嵌入任何项目的 WebAssembly 运行时,占用空间最小,解释器性能惊人,一直是王者般的存在Wasmtime 从 v0.40 版本升级到 v3.0.1 版本,版本 4 即将推出。 每个版本都是更新 Cranelift 的机会,它基于代码生成器。 最近对 Cranelift 进行了很多改进,所以现在是时候看看它们如何反映在基准测试中了。Wasmer 不断发布独特的工具和功能,例如:生成独立二进制文件的能力,同时单通道编译器也得到了更新。Wamr 看到了一堆新版本, 预构建的二进制文件现在也可用。Wazero 是一种新的、零依赖的 Go 运行时,虽然还没有达到 V1.0 版,但前途光明。Node 对 WebAssembly 和 WASI 有很好的支持。 然而,后者在默认情况下仍未启用,需要命令行标志--experimental-wasm-bigint --experimental-wasi-unstable-preview1Bun 以 Node 的现代替代品出现,基于 JavaScriptCore。 它不支持开箱即用的 WASI,但 wasmer-js 可以完美地模拟它。GraalVM 现在包括对 WebAssembly 的实验性支持。

大多数其他运行时项目,比如:Asmble、Wac、Windtrap、Wagon、Py-Wasm 等似乎已被放弃。

4.将 C 代码编译为 WebAssembly

WebAssembly 包含多项改善性能的提案,例如:执行尾调用优化(tail-call optimizations)的能力、对 128 位向量(128-bit vectors)、线程和批量内存操作 (memcpy/memset) 的支持。

但是,所有这些提案只是建议,是否实现、是否默认启用取决于运行时本身。理想情况下,每个 WebAssembly 应用程序都应该针对多个目标进行分发(wasm32-wasi-generic、wasm32-wasi-generic+simd128、wasm-wasi-generic+simd128+threads+tail_calls 等)。 但是这很难管理,运行时甚至没有实现自动选择合适目标的能力。

图片来源:

因此,在实践中,要编写与各种运行时兼容的应用程序,使用这些提案(proposals)绝非最优选择。 但是,批量内存操作可能是例外:绝大多数运行时都支持,并且在 wasm3、wasmedge、wasmer、wasm2c 和 node 中默认启用。

为了对上述运行时进行基准测试,需要为 WebAssembly 的 wasm32-wasi 风格构建库。为此, libsodium 用 C 语言编写,必须使用可以针对 wasm32-wasi 的 C/C++(交叉)编译器:来自 Zig 工具链的 zig cc 命令。

Zig:是一种命令式的、通用的、静态类型的、编译的系统编程语言,由AndrewKelley设计。该语言的设计是为了实现鲁棒性、优化和可维护性,并支持编译时的泛化、反射和执行、交叉编译和手动内存管理。

以前,将 libsodium 编译为 wasm32-wasi 需要为编译器设置 zig cc --target=wasm32-wasi 命令。 但是库源代码现在包含一个 Zig 构建文件,可以用作 autotools 的替代品。

autotools:专门用来生成Makefile的一系列工具,包括:autoscan、aclocal、autoheader、autoconf、automake等等。

因此,对于此基准测试,库是使用以下命令构建的:

zig build \  -Dtarget=wasm32-wasi \  -Drelease-fast \  -Denable_benchmarks=true \  -Dcpu=generic+bulk_memory

使用的 Zig 版本是 0.11.0-dev.863+4809e0ea7,libsodium 的版本是 58ae64d319246e5530c,生成的 zig-out/bin/ 文件夹包含每个基准测试的 WebAssembly 文件。

5.方法论&比较

测试输出会包含运行所花费的时间。 因此,基准测试忽略了各个运行时可能有的设置/销毁(setup/teardown)时间。 同样,提前编译器(ahead-of-time compilers)所需的编译时间也有意不测量, 只衡量实际执行性能。

该基准测试在 Scaleway 提供的 Zen 2 CPU 上运行。运行时,该实例上没有其他任何东西在运行,测试固定在单核 CPU 上,每个测试运行 200 次以进一步降低噪音。

在运行之前,WebAssembly 文件使用 wasm-opt -O4 --enable-bulk-memory 命令(binaryen 工具的一部分)进一步优化。

webassembly-benchmarks 的地址:

以下运行时经过基准测试:

iwasm:它是 WAMR 包的一部分 ,从其存储库下载的预编译文件wasm2c:包含在用于引导编译器的 Zig 源代码中wasmer 3.0:使用网站上显示的命令安装,3 个后端已经过单独测试wasmtime 4.0:从源代码编译通过 Ubuntu 软件包安装的 node v18.7.0bun 0.3.0:过网站上的 show 命令安装来自 git rev 796fca4689be6 的 wazero,从源代码编译

GraalVM 无法参与基准测试,因为它对 WASI 的支持非常有限,比如:缺少生成随机数所需的 random_get() ,而且也不支持大容量内存操作。

测试也已经按类别分组,与之前的基准迭代相比,显著提高了可读性,数据结果已中位数归一化。 X 轴表示与中值性能 (1) 相比,运行时要慢多少。 因此,越小越好,结果为 2 意味着运行时间比中位数慢 2 倍。

AEAD 基准

经过身份验证的加密测试具有一个使用不同参数多次调用(针对每个输入块)的小函数, 性能通常取决于自动矢量化和寄存器分配。似乎没有任何运行时能够对内容进行自动矢量化,因此结果非常相似。

自动矢量化:是2012年公布的地理信息系统名词,定义按照一定算法把栅格数据自动转变成用点、线和面表示的矢量数据形式的过程。

Authentication benchmark

该测试基于 SHA-2(SHA-256、SHA-512、SHA-512/256)哈希函数的软件实现。与 AEAD 一样,它们依赖于使用不同参数多次调用的函数。 但是,还有很多常量,编译器有机会内联。

SHA-2,名称来自于安全散列算法2(英语:Secure Hash Algorithm 2)的缩写,一种密码散列函数算法标准,由美国国家安全局研发,属于SHA算法之一,是SHA-1的后继者。

SHA-2下又可再分为六个不同的算法标准,包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256

在这些测试中,wasmedge 与使用 LLVM 后端的 Wasmer 相比表现不佳,考虑到它们都是基于 LLVM 的事实,这是出乎意料的。以 bun 为代表的 JavaScriptCore 引擎在这些测试上显示出很大的改进空间,但是它似乎缺少单通道编译器所具有的优化通道。

Box benchmark

这些测试结合了按位运算和算术(bitwise operations and arithmetic),结果表现非常相似,除了无法承受昂贵优化的单遍编译器。

Arithmetic over elliptic curves

很多算术运算,大多使用 64 位寄存器。不出所料,结果与 Box benchmark 相似。

Hashing benchmark

BLAKE2B 和 SHA-2 散列, 这类似于身份验证基准。bun 仍然比其他运行时慢,即使 BLAKE2B 不像 SHA-2 那样使用大型常量表。 在哈希函数中肯定存在一种 JavaScriptCore 还不能正确优化的模式。

BLAKE2B:是一个强调快速、安全与简单的Hash算法,并且目前被用来替代 MD5和 SHA1。因为它可以在不耗费更多资源的情况下提供更好的安全性。

Key exchange and key derivation benchmark

与哈希函数相同,但这些函数的输入有很大不同:这里的输入很短,忽略单遍编译器,结果非常接近。

Metamorphic benchmark

显然没有太多的优化空间:除了常见的例外,所有运行时的性能几乎完全相同,Wazero 除外。这些测试执行内存分配并需要大量随机数(通过 WASI 系统调用获得)。 这可能是导致 Wazero 如此缓慢的原因,而不是代码是如何优化的。

One-time authentication benchmark

这是对 Poly1305 函数的基准测试,是使用 64 位寄存器的简单算术。多遍编译器似乎应用了相同的优化;单程编译器也是如此。

Poly1305:是一种带密码的消息摘要算法

Password hashing benchmark

密码散列函数依赖于不可预测位置的内存读写。除了 C 编译器已经完成的工作之外,可能没有太多需要优化的地方。

Diffie-Hellman benchmark

有限域上的算术, 优化机会包括使用 ADCX/ADOX 进行进位传播。总的来说,所有运行时都表现得很好,Wazero 除外,它比使用 singlepass 后端的 Wasmer 慢得多。

adcx 和 adox 指令是 adc 指令的扩展, 设计用于支持两个独立的运载链。

Secretbox benchmark

在这里,使用 salsa20、chacha20 和 poly1305 对经过身份验证的加密进行基准测试。最适合 32 位和 64 位寄存器的简单算术。

Keygen benchmark

这些测试都是关于随机性提取的,没有太多需要优化的地方。 这些测试主要测量 WASI 调用获取随机字节的开销,并且可能测量一般 WASI 调用的开销。

node 和 bun 之间的区别是意料之中的,因为 node 原生支持 WASI,而 bun 需要 wasmer.js 仿真层。 bun 很快会包含本机 WASI 支持,从而可以使它与其他运行时处于同一水平。

然而,wasmedge 没有 WASI 仿真接口, 在 wasmedge 中调用外部函数可能比在其他运行时有更多的开销。

Signature benchmark

在椭圆曲线上进行算术运算,触发常见的优化过程,并进行极少的 WASI 系统调用。在这里,同样基于 LLVM 的 wasmedge 设法比使用 LLVM 后端的 wasmer 更快。

Utilities benchmark

编解码器、比较函数和其他简单的辅助函数,旨在有意阻止编译器优化。 正如预期的那样,跨运行时的性能非常相似。

Stream ciphers benchmark

Salsa20 和 Chacha20 流密码,因此,主要是涉及 32 位值向量的按位算术。 有自动矢量化的机会,但这并非微不足道。性能非常相似,单通道编译器除外。

Salsa20加密和ChaCha20特别相似,ChaCha20是对Salsa20做了调整,数据bit扩散更快

Cumulative benchmark

iwasm、wasmer(LLVM 后端)和 wasmedge 都使用 LLVM 进行代码生成。 直觉上,性能已经非常接近,但事实并非如此。

iwasm,基准测试的新成员(至少在 AOT 模式下),一直是最快的运行时, 性能与 wavm 非常接近,可以将其视为替代品。

在 LLVM 类别中,考虑到项目从一开始就非常注重性能,预计 wasmedge 会领先。 结果有点令人失望,其与 V8(Node.js)差不多。

另一方面,使用 cranelift 进行代码生成的运行时(带有该后端的 wasmer 和 wasmtime)的性能几乎相同。

真正令人印象深刻的是基于 LLVM 的结果和基于 cranelift 的结果非常接近。 cranelift 代码生成器性能已经变得和 LLVM 非常接近。 考虑到 cranelift 是一个相对年轻的项目,由一个非常小的团队从头开始编写,绝对是隐藏的大佬般存在。

以 bun 为代表的 JavaScriptCore 引擎表现差强人意。 作为一个 JavaScript 引擎,速度非常快。 但是作为 WebAssembly 引擎却表现平平。 这可能与缺乏原生 WASI 实现有关,但还有更多优化空间。

wasmer (有 singlepass 后端)和 wazero 的共同点是它们以流方式快速编译。 对于一些涉及不可信输入的应用程序来说,这是一个关键属性。另一方面是无法进行昂贵的优化,需要做一个权衡。

wazero 的结果也不是很好。 但由于它与 Go 语言的无缝集成涉及额外的限制,尤其是在寄存器数量有限的 Intel CPU 上, wazero 在 ARM CPU 上的性能可能会好得多。无论如何,wazero 团队都非常重视性能,已经在寻找潜在的优化。

与原生代码比较

上图表示使用最快的 WebAssembly 运行时运行单个测试所花费的时间与将库编译为本机代码并进行特定于体系架构优化的相同测试之间的比率。

隐藏了两个异常值:aegis128l 和 aegis256 测试。 本机代码利用本机 CPU 指令来计算 AES 轮次。 另一方面,WebAssembly 无法利用这些指令,必须退回到缓慢的软件实现。

结果,这些基于 AES 的测试在运行 WebAssembly 时比本机代码慢 80 倍,但是这并不代表大多数应用程序。 然而,它强调了 WebAssembly 对依赖 AES 的加密操作的真正限制。

忽略这一点,当使用最快的运行时时,WebAssembly 仅比具有特定架构优化的本机代码慢 2.32 倍(中位数),已经非常不错了!

6.四类 WebAssembly 运行比较

有四类 WebAssembly 运行时:

解释器:在这个类别中,wasm3 可能是最好的选择,而且也非常容易嵌入具有优秀性能的基于 LLVM/Cranelift/V8 的运行时基于 JavaScriptCore 的运行时,略微落后于其他运行时单程编译器(Single-pass compilers)6.1 iwasm

如果正在寻找最佳性能表现者,可以选择 iwasm,其是 WAMR 项目的一部分。iwasm 有一个简单的 C API,以及 Python 和 Go 的绑定。 所以在这些语言中,其实是相当好用的。

iwasm 运行时本身非常小 (50 KB),内存占用也很小。 它可以根据应用程序进行定制,以进一步减少体积,使其成为受限环境的绝佳选择。 特别是因为它开箱即用地支持: Zephyr、VxWorks、NuttX 和 RT-Thread 等平台。

6.2 基于 LLVM/Cranelift/V8 的运行时

node、wasmtime、wasmedge 和 wasmer 属于同一类,还没有稳定的 API, 特别是 Rust API 。 如果应用程序依赖于 wasmer 或 wasmtime 的 Rust API,需要做好心理准备。

然而,C API 要稳定得多:wasmtime 的 C API 最近只有一个重大变化,而 wasmer 彻底改造了 API 一次,此后一直保持稳定。wasmedge C API 不同且具有更多的特性。 虽然 break changes 仍然会发生,但通常很小且易于处理。

node(实际上的V8)拥有迄今为止最稳定的 API,尽管 node 中的 WASI 支持仍被认为是实验性的。因此,node(或嵌入式时的 V8+uvwasi)是一个很好、安全、保守的选择,对于 WebAssembly,切换到其他方案并没有太多的性能提升,V8 也支持全模块 AOT 编译。

然而,为了运行 WebAssembly 代码,必须集成整个 V8 引擎, 这是一个巨大的依赖。 对于还需要支持 JavaScript 的应用程序来说这不是问题,但对于只需要 WebAssembly 的应用程序来说绝对是杀鸡用牛刀。

这就是 wasmtime、wasmedge 和 wasmer 发挥作用的场景。 它们更小,并包含适合运行第三方代码的诸多功能。对于大多数用户而言,这三个运行时之间没有显著差异。 它们具有相似的功能(例如 AOT 编译)并以相同的方式运行代码,速度大致相同。不过,它们具有一些独特的功能,可以对某些应用程序产生影响。

wasmer

wasmer 拥有最大的生态,其中的库使其非常容易从多种编程语言以及 PostgreSQL 和 Visual Studio Code 等应用程序中使用。wasmer 还包括为所有支持的平台生成独立二进制文件的能力,有一个包管理器等等。 尽管有一些重大变化,但它似乎更注重 API 稳定性而不是替代方案,这使其成为计划长期维护的应用程序的合理选择。

wasmedge

wasmedge 是来自 CNCF 的运行时,Docker 用来运行带有 WebAssembly 应用程序的容器。 因此,即使这不是您选择的运行时,也强烈建议测试 WebAssembly 代码是否在其上正常运行,因为它的受欢迎程度可能会飙升。

wasmedge 带有网络支持,尽管目前仅限于 Rust 和 JavaScript 应用程序。 但是 wasmedge 最好的特性之一是它的插件系统,允许在不改变核心运行时的情况下进行扩展。 开箱即用,它带有实现 wasi-nn 和 wasi-crypto 提案的插件,以及一个 HTTP 客户端插件和一种以受控方式运行外部命令的简单方法。

wasmedge 包含可轻松将其嵌入到 C、Rust、Go、JavaScript 和 Python 应用程序中的库。

wasmtime

wasmtime 在每个漏洞之后都进行了安全披露,并竭尽全力防止类似漏洞再次发生。小心翼翼地进行更改,并且不断对项目进行模糊测试以发现新的错误。

如果目的是在浏览器环境之外运行任意、不受信任的代码,wasmtime 感觉是最安全的选择。在没有任何可选功能的情况下,链接到 libwasmtime 的最小可执行文件重量为 22 MB,即使使用 AOT 并且未调用编译函数也是如此。

这比 wasmer(由 wasmer 权重 16 MB 生成的基本独立可执行文件)大一点,但远不及 wasmedge,后者仅提供一个权重不小于 45 MB 的共享库,与 node(46 MB)一样大 !

总而言之,很难从以上三者中做出最优选择。 但是,使用它们中的任何一个都不会出错,除非应用程序需要它们的独特功能之一。

3.JavaScriptCore

JavaScriptCore 之于 Safari 就像 V8 之于 Chrome:一个可移植的、功能齐全的 JavaScript 引擎,由优秀的多级解释器和编译器支持。

两者都用于当前绝大多数主流 Web 浏览器,也在 node (V8) 和 bun (JavaScriptCore) 等非浏览器环境中使用。JavaScriptCore 的性能非常出色,甚至超过 V8 。JavaScriptCore 在现有的编译器之上构建,最终也获得了对 WebAssembly 的支持。

不幸的是,JavaScriptCore 目前在 WebAssembly 上的表现不如 V8。 截至目前,如果正在寻找 JavaScript+WebAssembly 引擎,那么 V8 可能是最好的选择。不过,JavaScriptCore 可能会很快修复,从而获得更好的性能表现。

Wazero

要在 Go 应用程序中嵌入 WebAssembly 模块,wazero 应该是最佳选择,除非性能是硬伤。

wazero 完全用 Go 编写,零依赖。 其具有许多优点:安全性、可移植性、与语言的完美集成以及将其添加到现有项目中是微不足道的,与替代方案相比,增加的开销可以忽略不计。

wasm2c

WebAssembly 编译器是否可以包含 WebAssembly 运行时以运行其自身的 WebAssembly 版本以再次编译自身? 如果听起来令人困惑,请阅读 Zig 如何摆脱 C++ 编译器。

wasm2c 是一个 WASM 到 C 的转译器。 transpiler 在几天内编写,非常简单,大约 2000 行独立代码,并且不会试图变更或优化。 它只是将单个 WebAssembly 操作码逐字翻译成非常愚蠢的 C 代码,并让 C 编译器负责所有优化工作。 它还包括对 WASI 的最小支持。

除了 C 编译器之外,wasm2c 还是零依赖,即运行时开销是零, 内存开销也可以忽略不计。看看基准测试的结果,这种方法的性能非常出色。 事实上,它在每项测试中都与最快的 WebAssembly 运行时并驾齐驱。

但有一个问题。 WebAssembly 的两个主要卖点是可移植性(毕竟这是字节码),以及保证应用程序无法访问任意内存位置。从 wasm2c 的输出编译的代码提供了前者,即 WebAssembly 代码的单个副本可以在多个平台上运行。但是,wasm2c 没有采取任何措施来强制满足后者。 这样就需要在堆栈之前和线性内存段之后添加保护页,或者额外的操作,例如对加载/存储操作中使用的指针应用掩码,以将它们保持在安全范围内。

但是,当要运行的 WebAssembly 代码是可信的时,这种非常紧凑和简单的方法配合得非常好,是引导编译器的绝佳决定。利用这种方法,w2c2 是一个非常有前途的项目,值得关注(声称只比本机代码慢 7%!)

7.WebAssembly 的未来已来

在过去的两年时间里,WebAssembly 运行时的世界发生了很大的变化。伴随新功能的集成,性能的改进(cranelift 现在与 LLVM 一样快),真正做到了江山代有人才出。 同时对开发者而言,这也预示着不再有明显的赢家,只有好的选择!

同时,还看到了 WebAssembly 在浏览器环境之外的新应用,以及跨编程语言使用 WebAssembly 的一致方式(Extism)。 WebAssembly 也逐渐成为机密计算的重要组成部分(比如:Vera Cruz、Enarx、Inclavare)。

语言和工具中的 WebAssembly 支持也得到了改进,Swift 现在可以输出 WebAssembly 代码。 可以使用 zig cc 将 C/C++ 代码编译为 WASI,而不是手动修补 clang 或必须安装另一个完整的 LLVM 副本,同时 tinygo 也逐渐变得成熟。 以 WebAssembly 为目标的新编程语言诞生了。

总之,WebAssembly 生态系统的未来绝对是光明的!

8.本文总结

本文主要和大家介绍2023 年 WebAssembly 各个运行时性能比较!因为篇幅有限,文章并没有过多展开,如果有兴趣,可以直接在我主页继续阅读,但是文末的参考资料提供了大量优秀文档以供学习。最后,欢迎大家点赞、评论、转发、收藏!

参考资料

英文链接:

英文作者:Frank Denis (Jedi/Sector One)

标签: #ubuntu文本搜索gra