$ rustc --target= wasm32-unknown-unknown -C opt-level= 3 -o rust.wasm rotate.rs
在执行 wasm-opt、wasm-strip 和 gzip 后,生成了 1.6KB 的 wasm 模块。虽然它仍然比 C 和 AssemblyScript 生成的模块大,但足够小,可以被视为轻量级模块。
注意 :根据 Twiggy 的说法,文件大小的主要贡献者是 core::fmt,这是一个用于将数据转换为字符串的模块(类似于 C 的 printf())。可能会触发异常的代码路径会使用它,因为它们会生成人类可读的异常消息。Rust 的 WebAssembly 团队已意识到这一点,并正在积极改进。
在仅根据文件大小就得出结论之前,请注意,我们此次改进是为了优化性能,而不是文件大小。我们如何衡量效果,以及取得了怎样的成效?
如何进行基准测试
尽管 WebAssembly 是一种低级字节码格式,但仍需要通过编译器发送,以生成特定于主机的机器码。与 JavaScript 一样,编译器的工作方式分为多个阶段。简单来说:第一阶段的编译速度要快得多,但生成的代码运行速度往往较慢。模块开始运行后,浏览器会观察哪些部分被频繁使用,并通过优化程度更高但速度较慢的编译器发送这些部分。
我们的用例很有趣,因为用于旋转图片的代码将被使用一次,也许两次。因此,在大多数情况下,我们永远无法获得优化编译器的好处。在进行基准测试时,请务必注意这一点。在循环中运行 WebAssembly 模块 1 万次会产生不切实际的结果。为了获得真实的数据,我们应运行模块一次,并根据单次运行的数据做出决策。
注意 :理想情况下,我们应该自动执行重新加载页面和运行模块一次,然后多次执行该过程。我们认为,只需进行几次手动运行,就可以根据这些平均值做出明智的决策。
这两个图表是对同一数据的不同视图。在第一个图表中,我们按浏览器进行比较;在第二个图表中,我们按所用语言进行比较。请注意,我选择了对数时间尺度。值得注意的是,所有基准测试都使用了相同的 1600 万像素测试图片和相同的主机,但有一款浏览器无法在同一台机器上运行。
无需过多分析这些图表,我们就可以清楚地看到,我们解决了最初的性能问题:所有 WebAssembly 模块的运行时间均在 500 毫秒左右。这证实了我们在开头所说:WebAssembly 可为您提供可预测 的性能。无论我们选择哪种语言,浏览器和语言之间的差异都很小。确切地说:所有浏览器中 JavaScript 的标准差约为 400 毫秒,而所有浏览器中所有 WebAssembly 模块的标准差约为 80 毫秒。
另一个指标是创建 WebAssembly 模块并将其集成到 squoosh 所需的工作量。很难为“努力程度”分配一个数字值,因此我不会创建任何图表,但我想指出以下几点:
AssemblyScript 的使用非常顺畅。它不仅允许您使用 TypeScript 编写 WebAssembly,让我的同事能够轻松进行代码审核,还能生成无粘合剂的 WebAssembly 模块,这些模块非常小且性能出色。TypeScript 生态系统中的工具(例如 prettier 和 tslint)应该可以正常使用。
Rust 与 wasm-pack 搭配使用也非常方便,但在需要绑定和内存管理的大型 WebAssembly 项目中更为出色。为了实现具有竞争力的文件大小,我们不得不稍微偏离常规路径。
C 和 Emscripten 开箱即用即可创建一个非常小且高性能的 WebAssembly 模块,但如果不敢深入研究粘合代码并将其缩减到仅包含必需内容,总大小(WebAssembly 模块 + 粘合代码)最终会非常大。
因此,如果您有 JS 热路径,并且希望使其更快或更符合 WebAssembly 的规范,应该使用哪种语言?与往常一样,对于效果问题,答案是:取决于具体情况。我们发布了什么?
注意 :再次提醒您,两个 轴都是对数轴,x 轴的范围为 2000 字节,而 y 轴的范围为 10 秒。
比较我们所用不同语言的模块大小 / 性能权衡,最佳选择似乎是 C 或 AssemblyScript。我们决定发布 Rust 。做出此决定的原因有很多:Squoosh 中目前提供的所有编解码器都是使用 Emscripten 编译的。我们希望拓展对 WebAssembly 生态系统的了解,并在生产环境 中使用其他语言。AssemblyScript 是一个不错的替代方案,但该项目相对较新,编译器不如 Rust 编译器成熟。
虽然在散点图中,Rust 与其他语言的文件大小差异看起来非常明显,但实际上差异并不大:加载 500B 或 1.6KB 甚至超过 2G 的文件都需要不到 1/10 秒的时间。Rust 有望很快缩小模块大小方面的差距。
在运行时性能方面,Rust 在各浏览器中的平均速度比 AssemblyScript 快。尤其是在大型项目中,Rust 更有可能生成运行速度更快的代码,而无需手动进行代码优化。不过,这不应妨碍您使用自己最熟悉的设备。
尽管如此,AssemblyScript 还是一个了不起的发现。借助它,Web 开发者无需学习新语言即可生成 WebAssembly 模块。AssemblyScript 团队的响应非常及时,并且正在积极改进其工具链。我们日后一定会密切关注 AssemblyScript。
更新:Rust
在本文发布后,Rust 团队的 Nick Fitzgerald 向我们推荐了他们出色的 Rust Wasm 图书,其中包含关于优化文件大小的部分 。按照其中的说明(最值得注意的是启用链接时间优化和手动 panic 处理)操作后,我们能够编写“正常”Rust 代码,并恢复使用 Cargo(Rust 的 npm),而不会增加文件大小。经过 gzip 压缩后,Rust 模块的大小为 370B。如需了解详情,请参阅我在 Squoosh 上创建的 PR 。
特别感谢 Ashley Williams 、Steve Klabnik 、Nick Fitzgerald 和 Max Graey 在此过程中提供的所有帮助。
如未另行说明,那么本页面中的内容已根据知识共享署名 4.0 许可 获得了许可,并且代码示例已根据 Apache 2.0 许可 获得了许可。有关详情,请参阅 Google 开发者网站政策 。Java 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2019-02-14。
[[["易于理解","easyToUnderstand","thumb-up"],["解决了我的问题","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["没有我需要的信息","missingTheInformationINeed","thumb-down"],["太复杂/步骤太多","tooComplicatedTooManySteps","thumb-down"],["内容需要更新","outOfDate","thumb-down"],["翻译问题","translationIssue","thumb-down"],["示例/代码问题","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["最后更新时间 (UTC):2019-02-14。"],[],[]]