如何使用WebAssembly将Web应用的速度提高20倍(案例研究)
Posted Web前端程序员
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用WebAssembly将Web应用的速度提高20倍(案例研究)相关的知识,希望对你有一定的参考价值。
快速总结: 在本文中,我们探讨如何通过使用编译的WebAssembly替换较慢的javascript计算来加速web应用。
如果您还没有听说过WebAssembly,下面是对它的描述(太长,不要读): WebAssembly是一种与JavaScript一起运行在浏览器中的新语言。是的,没错。JavaScript不再是唯一一种在浏览器中运行的语言!
但是,除了“不是JavaScript”之外,它的独特之处在于,您可以从C/C++ /Rust(以及更多!)等语言将代码编译到WebAssembly,并在浏览器中运行它们。因为WebAssembly是静态类型的,使用线性内存,并以紧凑的二进制格式存储,所以它的速度也非常快,最终可能允许我们以“接近本机”的速度运行代码,即以接近于在命令行上运行二进制代码的速度运行代码。最大程度的在浏览器中使用现有工具和库的能力,以及相关的加速潜力,是WebAssembly在web应用中如此引人注目的两个原因。
到目前为止,WebAssembly已被用于各种应用程序,从游戏(如Doom 3)到将桌面应用程序移植到web(如Autocad和 Figma)。它甚至可以在浏览器之外使用,例如作为一种用于无服务器计算的高效且灵活的语言。
本文是一个使用WebAssembly加速数据分析web工具的案例研究。为此,我们将使用一个用C语言编写的执行相同计算的现有工具,将其编译为WebAssembly,并使用它来替换缓慢的JavaScript计算。
备注: 本文深入研究了一些高级主题,比如编译C代码,但是如果您没有这方面的经验,请不要担心,您仍然能够跟随并理解WebAssembly的功能。
背景
我们将使用的web应用是fastq.bio,它是一个交互式网络工具,为科学家提供快速预览他们的DNA测序数据的质量的功能;测序是我们读取DNA样本中的“字母”(即核苷酸)的过程。
下面是此应用程序运行的截图:
fastq.bio 运行截图
我们不会详细讨论计算的细节,但是简单地说,上面的图为科学家提供了测序进行得如何的一种直观感觉,并被用于快速识别数据质量问题。
尽管有许多命令行工具可以生成这样的质量控制报告,但是fastq.bio的目标是在不离开浏览器的情况下提供一个数据质量的交互式预览。对于不熟悉命令行的科学家来说,这尤其有用。
应用程序的输入是一个纯文本文件,由测序仪器输出,包含DNA序列列表和DNA序列中每个核苷酸的质量分数。该文件的格式称为“FASTQ”,所有该应用由此而得名fastq.bio。
Fastq.Bio: JavaScript 实现
在fastq.bio的原始版本中,用户首先从计算机中选择一个FASTQ文件。通过File对象,应用程序从随机字节位置开始读取一小块数据(使用FileReader API)。在该数据块中,我们使用JavaScript执行基本的字符串操作并计算相关指标。其中一个指标帮助我们跟踪我们通常在DNA片段的每个位置上看到的A、C、G和T的数量。
一旦该数据块的指标计算完成后,我们就使用Plotly.js交互地绘制图表,然后继续处理文件中的下一个块。将文件分成小块处理的原因仅仅是为了改进用户体验;一次性处理整个文件将花费太长时间,因为FASTQ文件通常是几百GB的。我们发现,块大小在0.5 MB到1 MB之间会使应用程序更加无缝衔接,并将更快地向用户返回信息,但是这个数值会根据您的应用程序的细节和计算量的大小而变化。
我们最初的JavaScript实现架构相当简单:
fastq.bio的JavaScript实现架构
红色的框是我们进行字符串操作来生成指标的地方。该框是应用程序中计算密集型的部分,这自然使它成为使用WebAssembly进行运行时优化的好的候选者。
Fastq.Bio: WebAssembly 实现
为了探索我们是否可以利用WebAssembly来加速我们的web应用程序,我们搜索了一个现成的工具来计算FASTQ文件上的QC指标。具体来说,我们寻找了一个用C/ C++ /Rust编写的工具,这样它就可以移植到WebAssembly,而且这个工具已经得到了科学界的验证和信任。
经过一些研究,我们决定使用 seqtk,这是一个用C语言编写的常用的开源工具,可以帮助我们评估测序数据的质量(通常用于操作这些数据文件)。
在编译到WebAssembly之前,让我们首先考虑如何将seqtk编译为二进制文件,以便在命令行上运行它。根据Makefile,您需要用到gcc编译器:
另一方面,要将seqtk编译到WebAssembly,我们可以使用Emscripten toolchain,它为现有的构建工具提供了临时替换,从而使在WebAssembly中工作更加容易。如果您没有安装Emscripten,您可以下载我们在Dockerhub上准备的docker镜像,里面有您需要的工具(您也可以从头开始安装,但这通常需要一段时间):
在容器内部,我们可以使用emcc编译器代替gcc:
如您所见,编译为二进制和WebAssembly之间的差异是最小的:
我们让Emscripten生成一个.wasm和.js来处理WebAssembly模块的实例化,而不是输出二进制文件seqtk
为了支持zlib库,我们使用USE_ZLIB标志; zlib是非常常见的库,它已经被移植到WebAssembly, Emscripten会在我们的项目中包含它
我们启用了Emscripten的虚拟文件系统,这是一个类-POSIX文件系统(这里是源码),但是它在浏览器的RAM中运行,当您刷新页面时就会消失(除非您使用IndexedDB将其状态保存在浏览器中,但这是另一篇文章的内容)。
为什么是一个虚拟文件系统? 为了回答这个问题,我们来比较一下如何在命令行上调用seqtk和使用JavaScript调用编译后的WebAssembly模块:
访问虚拟文件系统非常强大的,因为这意味着我们不必重写seqtk来处理字符串输入而不是文件路径。我们可以将一块数据作为data.fastq文件挂载在虚拟文件系统上,并简单地调用seqtk的main()函数。
将seqtk编译到WebAssembly后,下面是新的fastq.bio的架构:
使用WebAssembly + WebWorkers实现的fastq.bio架构
如图所示,我们没有在浏览器的主线程中运行计算,而是使用WebWorkers,它允许我们在后台线程中运行计算,从而避免对浏览器的响应性产生负面影响。具体来说,WebWorker控制器启动Worker并管理与主线程的通信。在Worker端,一个API执行它接收到的请求。
然后,我们可以要求Worker对刚刚挂载的文件运行seqtk命令。当seqtk运行完毕时,Worker通过一个Promise将结果发送回主线程。一旦接收到消息,主线程就使用结果输出来更新图表。与JavaScript版本类似,我们以块的形式处理文件,并在每次迭代中更新可视化。
性能优化
为了评估使用WebAssembly是否确实有好处,我们使用每秒可以处理多少读取量这个指标来比较JavaScript和WebAssembly实现。我们忽略了生成交互式图形所花费的时间,因为这两种实现都使用JavaScript来实现此目的。
如图所示,我们已经看到大约9倍加速:
使用WebAssembly,我们可以看到与最初的JavaScript实现相比,速度提高了9倍。
这已经非常好了,因为它相对容易实现(只要当您理解了WebAssembly!)。
接下来,我们注意到,虽然seqtk输出了很多通常比较有用的QC指标,但我们的应用程序实际上并没有使用或绘制大多数指标。通过删除一些我们不需要的指标的输出,我们可以看到一个更大的13倍的速度提升:
删除不必要的输出可以进一步提高性能。(大预览)
这又是一个很大的改进,因为它很容易实现——通过从语法上注释掉不需要的printf语句。
最后,我们研究了另一个改进。到目前为止,fastq.bio方式通过调用两个不同的C函数来获得所需要的指标,每个函数计算一组不同的指标。具体来说,一个函数以直方图的形式返回信息(即我们放入范围的值列表),而另一个函数将信息以DNA序列位置的函数返回。不幸的是,这意味着相同的文件块被读取两次,这是不必要的。
因此,我们将这两个函数的代码合并到一个函数中(尽管有些混乱,甚至不需要复习我的C!)。由于这两个输出的列数不同,所以我们在JavaScript端进行了一些调整,以便将它们理顺。但这是值得的:这样做让我们实现了大于20倍的加速!
最后,使代码只读取每个文件块一次可以提高大于20倍的性能改进。
警告
现在是提出警告的好时机。当您使用WebAssembly时,不要总是期望得到20倍的加速。您可能只得到2倍的加速或者20%的加速。或者,如果您在内存中加载非常大的文件时,或者需要在WebAssembly和JavaScript之间进行大量通信时,那么速度可能会变慢。
结论
简而言之,我们已经看到用调用编译后的WebAssembly来替换缓慢的JavaScript计算可以显著提高速度。由于这些计算所需的代码已经在C语言中存在,所以我们获得了重用可信工具的额外好处。正如我们提到过的,WebAssembly并不总是合适的工作工具(天哪!),所以要明智地使用它。
英文原文:https://www.smashingmagazine.com/2019/04/webassembly-speed-web-app/
译者:忧郁的红秋裤
以上是关于如何使用WebAssembly将Web应用的速度提高20倍(案例研究)的主要内容,如果未能解决你的问题,请参考以下文章
解读 WebAssembly 的 2020:Web 以外的进展与计划