本文讨论通过使用 WebAssembly 替换 JavaScript 计算来加速浏览器应用程序的案例。
WebAssembly - 它是什么?
简而言之,这是基于堆栈的虚拟机的二进制指令格式。 Wasm(简称)通常被称为编程语言,但事实并非如此。指令格式与 JavaScript 一起在浏览器中执行。
重要的是,WebAssembly 可以通过 C/C++、Rust、Go 等语言编译源代码来获得。这里使用统计类型和所谓的平面内存模型。如上所述,代码以紧凑的二进制格式存储,使其几乎与使用命令行运行应用程序一样快。这些功能导致了 WebAssembly 的普及。
我们提醒: 对于“Habr”的所有读者 - 使用“Habr”促销代码注册任何 Skillbox 课程可享受 10 卢布的折扣。
技能箱推荐: 实践课程
“移动开发者专业版” .
目前,Wasm 用于许多应用程序,从 Doom 3 等游戏到 Autocad 和 Figma 等 Web 移植应用程序。 Wasm 还用于无服务器计算等领域。
本文提供了使用 Wasm 加速分析 Web 服务的示例。为了清楚起见,我们采用了一个用 C 编写的工作应用程序,该应用程序被编译为 WebAssembly。结果将用于替换 JS 中表现不佳的部分。
应用改造
该示例将使用 fastq.bio 浏览器服务,该服务面向遗传学家。该工具可让您评估 DNA 测序(解密)的质量。
以下是应用程序实际运行的示例:
这个过程的细节不值得深究,因为对于非专业人士来说相当复杂,但简而言之,科学家可以通过上面的信息图来了解DNA测序过程是否顺利以及出现了哪些问题。
该服务有替代方案:桌面程序。但 fastq.bio 允许您通过可视化数据来加快工作速度。在大多数其他情况下,您需要能够使用命令行,但并非所有遗传学家都具备必要的经验。
一切都很简单。输入是以文本文件形式呈现的数据。该文件是由专门的测序工具生成的。该文件包含 DNA 序列列表和每个核苷酸的质量分数。文件格式为 .fastq,这就是该服务得名的原因。
JavaScript 中的实现
用户使用 fastq.bio 时的第一步是选择适当的文件。使用 File 对象,应用程序从文件中读取随机数据样本并处理该批次。 JavaScript 的工作是执行简单的字符串操作并计算指标。其中之一是不同 DNA 片段上核苷酸 A、C、G 和 T 的数量。
计算出必要的指标后,使用 Plotly.js 将它们可视化,并且该服务开始使用新的数据样本。进行分块是为了提高用户体验的质量。如果您一次处理所有数据,该过程将冻结一段时间,因为包含排序结果的文件占用数百 GB 的文件空间。该服务获取大小从 0,5 到 1 MB 的数据片段,并逐步处理它们,构建图形数据。
以下是它的工作原理:
红色矩形包含用于获得可视化的字符串转换算法。这是该服务中计算量最大的部分。值得尝试用 Wasm 替换它。
测试 WebAssembly
为了评估使用 Wasm 的可能性,项目团队开始寻找现成的解决方案,用于基于 fastq 文件创建 QC 指标(QC - 质量控制)。在用 C、C++ 或 Rust 编写的工具中进行搜索,以便可以将代码移植到 WebAssembly。此外,该工具不应该是“原始的”;需要已经经过科学家测试的服务。
结果,做出了有利于
在转换为 Wasm 之前,有必要先了解一下桌面版 seqtk 的编译原理。根据 Makefile,这就是您需要的:
# Compile to binary
$ gcc seqtk.c
-o seqtk
-O2
-lm
-lz
原则上,您可以使用 Emscripten 编译 seqtk。如果不存在,我们就凑合一下。
$ docker pull robertaboukhalil/emsdk:1.38.26
$ docker run -dt --name wasm-seqtk robertaboukhalil/emsdk:1.38.26
如果需要
在容器内,您可以轻松使用 emcc 作为 gcc 的替代品:
# Compile to WebAssembly
$ emcc seqtk.c
-o seqtk.js
-O2
-lm
-s USE_ZLIB=1
-s FORCE_FILESYSTEM=1
最小变化:
Emscripten 使用 .wasm 和 .js 来生成文件,而不是输出到二进制文件,这些文件用于运行 WebAssemby 模块。
USE_ZLIB 标志用于支持 zlib 库。该库已分发并移植到 WebAssembly,Emscripten 将其包含在项目中。
Emscrippten 虚拟文件系统已激活。这
要理解为什么需要虚拟文件系统,有必要将从命令行运行 seqtk 的方式与运行已编译的 WebAssembly 模块的方式进行比较。
# On the command line
$ ./seqtk fqchk data.fastq
# In the browser console
> Module.callMain(["fqchk", "data.fastq"])
获得对虚拟文件系统的访问是必要的,以免为字符串而不是文件输入重写 seqtk。在这种情况下,数据片段在虚拟 FS 中显示为 data.fastq 文件,并调用 main() seqtk。
这是新的架构:
该图显示,不是在主浏览器线程中进行计算,
seqtk 命令是使用 Worker 在已安装的文件上运行的。执行完成后,Worker 会以 Promise 的形式产生结果。当主线程收到消息时,结果将用于更新图。如此反复多次。
WebAssembly 性能怎么样?
为了评估性能的变化,项目团队使用了每秒读取操作数参数。由于两种实现都使用 JavaScript,因此不考虑构建交互式图表所需的时间。
使用开箱即用的解决方案时,性能提高了九倍。
这是一个非常好的结果,但事实证明,它还有优化的机会。事实是大量的QC分析结果并没有被seqtk使用,因此可以将其删除。如果这样做,结果比 JS 提高了 13 倍。
它是通过简单地注释掉 printf() 命令来实现的。
但这还不是全部。事实是,在这个阶段,fastq.bio通过调用不同的C函数来接收分析结果,每个函数计算自己的一组特征,从而使文件的每个片段被读取两次。
为了解决这个问题,决定将两个功能合二为一。结果,生产率提高了 20 倍。
值得注意的是,如此出色的成绩并不总是能够取得。在某些情况下,性能会下降,因此值得评估每种情况。
作为结论,我们可以说 Wasm 确实提供了提高应用程序性能的机会,但您需要明智地使用它。
技能箱推荐:
- 两年实践课程
“我是一名专业网络开发人员” .- 在线课程
《C#开发从0开始》 .- 实践年课程
《PHP 开发者从 0 到 PRO》 .
来源: habr.com