通常能找到比 WebAssembly 或 Rust 更简单的方法来做性能改进。
WebAssembly(Wasm) 最早是在 2015 年由 JavaScript 的创造者 Brendan Eich 提出的。继 JavaScript(JS) 之后,它是第一种得到普遍支持的语言。万维网联盟(W3C)在 2017 年开发了 WebAssembly,WebAssembly 允许网站用诸如 Rust、C/C++、Java、Python 等编程语言编写代码,并像 JavaScript 一样在 Web 浏览器中运行它。
随后,WebAssembly 迅速成为一种主流技术,被主要的浏览器供应商采用。从 WebAssembly 开始崭露头角那一天起,很多开发人员就在讨论一个问题:“WebAssembly 是否会杀死 JavaScript?”
虽然有很多人猜测 WebAssembly 的出现意味着 JavaScript 的寿终正寝,但 Zaplib 开源库的创建者现在给大家带来了一个否定的答案。
Zaplib 团队从编写代码到探索实际应用场景,总共花了一年时间,以失败告终后,他们发布了一篇出色的事后分析文章,告诉大家为什么说有时候“从 JavaScript 迁移到 WebAssembly 不值得”。
从失败中学到的东西往往比从成功中学到的要多得多,但是显然很少有人愿意把失败的经验拿出来分享。Zaplib 团队显然诚意十足,有网友评价说:“很多软件工程师都想方设法证明他们在一个问题上花费的时间和工作量是合理的”,“Zaplib 是我见过的不屈服于沉没成本谬误的最好例子。”
Zaplib 团队想干什么
Zaplib 是一套开源库,用于使用 WebAssembly 和 Rust 加速 Web 应用程序。它能帮助大家使用简单的 API 在 Rust 中编写高性能代码,并与现有 JavaScript 代码顺畅匹配。
Zaplib 的目标是降低在浏览器中构建性能密集型应用程序的门槛。虽然在 JS 之内也有办法让运行速度加快,但随着时间推移,大量优化元素也可能提升应用的维护难度。而在 Rust 中,开发者只需少量优化就能获得高性能,从而解放出时间和精力处理更重要的内容。
自从 2005 年左右开始转向多核处理器以来,越来越多的场景需要实现更高的性能,软件需要变得更加并行。Rust 是一种针对性能和安全性进行了优化的编程语言,许多应用程序已经使用 Rust 来显着提高加载时间和响应速度。而另一方面,Wasm 也一直在给大家带来一些非常惊人的性能提升,Figma 是使用 Wasm 的典型案例,Figma 文件是在 C++/Wasm 中处理的,这确实能他们带来巨大的速度提升。
另一方面,Zaplib 创始人JP Posma,他是一位具有 18 年编程经验的计算机科学家,认为使用手动内存管理(大量 ArrayBuffers)、WebWorkers 等在浏览器里开发密集内容的应用程序非常痛苦。
所以,他联合一些技术大佬一起开发了 Zaplib ,希望借此帮助大家提升应用程序的性能。5 个月前,他们还根据 MIT 许可和 Apache 许可(2.0 版)条款将 Zaplib 进行了开源:https://github.com/Zaplib/zaplib
他们表示,Zaplib 解决的是 JS 与浏览器速度很慢的问题,希望用户能将 JS 增量移植为 Rust/Wasm 加速应用程序运行,可以从小端口入手再逐步扩展,进而接管整个应用程序。从长远来看,这就是面向下一代堆栈(「Unity for apps」)的演变。
今年 2 月初,他们宣布基于这个开源库成立一家创业公司,并努力探索商业模式,希望有客户可以使用 Zaplib,围绕渐进式移植到 WebAssembly。
他们也希望借此弄清楚这个库到底适合哪些用户的需求,作为尝试,他们还曾把这套实验方案发布在 Hacker News 上,想看看会不会启发出某些有趣的 Zaplib 用例。
他们写了两篇流量非常好的文章,《Typescript 的速度与 Rust 持平:Typescript++诞生》(https://news.ycombinator.com/item?id=30947680)和《Show HN:Zaplib——使用 Rust+Wasm 加速你的 webapp》(https://news.ycombinator.com/item?id=30960509)。
但显然好流量也没有转化成“任何实际应用”,他们认为这已经很能说明问题了:“缺乏实际应用场景”。
为什么 Zaplib 毫无用处?
Zaplib 希望在 Rust 驱动的 WebAssembly 中一次一个部分地重写 Web 应用程序,从而将性能提升多达 10 倍。虽然想法不错,但在与试点用户合作之后,他们发现之前的预想并不完全靠谱。
在事后分析文章中,他们讲了四个试点合作案例:
用户 1:他们不仅实现了最终将整个应用移植为 Rust 的“整体愿景”,同时也似乎获得了增量移植的加速空间。Zaplib 团队花了一周时间,把此用户的模拟器移植到 Rust,并希望速度能够显著提升。然而,最终速度只快了 5%。在加速方法上,Zaplib 团队主要使用的是更快的线性代数库,但 JS 中也有类似的库。Rust 并未起到任何有决定意义的帮助。
用户 2:Zaplib 团队将此用户的渲染器移植到由 GPU 加速的 2d 渲染器。结果非常理想,但良好效果源自渲染的 GPU 加速特性,也就是 WebGL,跟 Rust/Wasm 没什么关系。用户也很犹豫到底要不要在自己的代码库中引入全新 Rust 工具链,而实际来看确实没有必要。
用户 3:他们是 Zaplib 的优秀用户,但使用的并非渐进式应用。如果 Zaplib 团队打算从零开始构建新应用,那他们的需求倒是比较合适,可问题在于:1)这样需要更大的 API 表面;2)无法与现有业务对接。
用户 4:在对设计原型进行基准测试时,Zaplib 团队确实看到了 10 倍性能改进。然而,这些原型是从零开始构建而成的,所以并不能直接拿来做一对一性能比较。换句话说,Zaplib 团队用 JS 重写没准也能得到类似的加速效果。性能提升的另一个重要来源,是使用了 GPU 加速渲染器,同样跟 Rust/Wasm 完全无关(与用户 2 的情况相同)。整个易用性(线性、零成本抽象)确实更好,原生构建也带来了 2 倍提速,但还不足以推动人们彻底转向新的堆栈。
最后,Zaplib 团队指出,在某些情况下,Rust 确实比 JS 更快,但这类情况比预想的要少,而且性能一般也就翻一倍,大多数情况下达不到 10 倍。
“只有真正依赖 Rust 的零成本抽象特性时,才能实现 10 倍的巨大收益——这要归功于内存布局和对垃圾回收(GC)的规避,因此处理 100 万个 Rust 微结构的速度确实比处理 100 万个 JS 对象更快。但这种情况其实相当罕见,在增量调整中就更别指望了。即使 10 倍性能改进基本不成立,工程师们自然不会愿意接受这样一套需要重新学习、重新维护的工具链和技术堆栈。
我们自己肯定不愿意,自然也不能强迫其他人。总之,要想实现性能改进,一般都有比转向 Rust/Wasm 更简单的方法。”
另外,他们还特地强调,虽然 Figma 在用 Wasm,但仔细观察就会发现,他们使用 Wasm 其实更多是个“历史遗留问题”——他们的目标是在 C++中构建以保护原生应用,而不是追求更高性能。Figma 文件是在 C++/Wasm 中处理的,这确实能带来巨大的速度提升,但真正让 Figma 性能脱颖而出的其实是他们的 WebGL 渲染器。
写在最后
大佬们的创业最终宣告失败了,否定了基于 Zaplib 建立初创公司的核心假设。
这并不意味着 WebAssembly 很糟糕或没有帮助。谷歌地球和 Photoshop 都被 WebAssembly 移植到了网络浏览器上,像微软这样的公司正在为更多的开发人员构建框架以进行同样的过渡,它的存在绝对是有原因的。但 JavaScript 在过去几年中也发生了显着的变化,在 Chrome、Microsoft Edge 和其他基于 Chromium 的浏览器中处理 JavaScript 代码的“V8”引擎不断变得更快。虽然 WebAssembly 已经为 Web 带来了几年前不可能存在的新一波应用程序,但不要指望所有 JavaScript 很快就会消失。
在博客文章最后,他们为自己失败的创业发出了感慨:“事实证明,基准测试和客户访谈很容易被自欺欺人式地理解成确凿证据。这次失利也让我们意识到:如果必然失败,那快速失败一定好过缓慢失败!”
参考链接:
https://zaplib.com/docs/blog_post_mortem.html?continueFlag=7dfc40344266025cf05d7577e9e0492b
https://sktodaysnews.com/03/05/2022/technology/javascript-web-apps-arent-going-anywhere/
评论 1 条评论