我们如何使用 WebAssembly 将 Web 应用程序加速 20 倍

我们如何使用 WebAssembly 将 Web 应用程序加速 20 倍

本文讨论通过使用 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 测序(解密)的质量。

以下是应用程序实际运行的示例:

我们如何使用 WebAssembly 将 Web 应用程序加速 20 倍

这个过程的细节不值得深究,因为对于非专业人士来说相当复杂,但简而言之,科学家可以通过上面的信息图来了解DNA测序过程是否顺利以及出现了哪些问题。

该服务有替代方案:桌面程序。但 fastq.bio 允许您通过可视化数据来加快工作速度。在大多数其他情况下,您需要能够使用命令行,但并非所有遗传学家都具备必要的经验。

一切都很简单。输入是以文本文件形式呈现的数据。该文件是由专门的测序工具生成的。该文件包含 DNA 序列列表和每个核苷酸的质量分数。文件格式为 .fastq,这就是该服务得名的原因。

JavaScript 中的实现

用户使用 fastq.bio 时的第一步是选择适当的文件。使用 File 对象,应用程序从文件中读取随机数据样本并处理该批次。 JavaScript 的工作是执行简单的字符串操作并计算指标。其中之一是不同 DNA 片段上核苷酸 A、C、G 和 T 的数量。

计算出必要的指标后,使用 Plotly.js 将它们可视化,并且该服务开始使用新的数据样本。进行分块是为了提高用户体验的质量。如果您一次处理所有数据,该过程将冻结一段时间,因为包含排序结果的文件占用数百 GB 的文件空间。该服务获取大小从 0,5 到 1 MB 的数据片段,并逐步处理它们,构建图形数据。

以下是它的工作原理:

我们如何使用 WebAssembly 将 Web 应用程序加速 20 倍

红色矩形包含用于获得可视化的字符串转换算法。这是该服务中计算量最大的部分。值得尝试用 Wasm 替换它。

测试 WebAssembly

为了评估使用 Wasm 的可能性,项目团队开始寻找现成的解决方案,用于基于 fastq 文件创建 QC 指标(QC - 质量控制)。在用 C、C++ 或 Rust 编写的工具中进行搜索,以便可以将代码移植到 WebAssembly。此外,该工具不应该是“原始的”;需要已经经过科学家测试的服务。

结果,做出了有利于 序列号。该应用程序非常流行,它是开源的,源语言是C。

在转换为 Wasm 之前,有必要先了解一下桌面版 seqtk 的编译原理。根据 Makefile,这就是您需要的:

# Compile to binary
$ gcc seqtk.c 
   -o seqtk 
   -O2 
   -lm 
   -lz

原则上,您可以使用 Emscripten 编译 seqtk。如果不存在,我们就凑合一下。 Docker镜像.

$ 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 虚拟文件系统已激活。这 类 POSIX FS,在浏览器内的 RAM 中运行。当页面刷新时,内存被清除。

要理解为什么需要虚拟文件系统,有必要将从命令行运行 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。

这是新的架构:

我们如何使用 WebAssembly 将 Web 应用程序加速 20 倍

该图显示,不是在主浏览器线程中进行计算, 网络工作者。此方法允许您在后台线程中执行计算,而不影响浏览器响应能力。好吧,WebWorker 控制器启动 Worker,管理它与主线程的交互。

seqtk 命令是使用 Worker 在已安装的文件上运行的。执行完成后,Worker 会以 Promise 的形式产生结果。当主线程收到消息时,结果将用于更新图。如此反复多次。

WebAssembly 性能怎么样?

为了评估性能的变化,项目团队使用了每秒读取操作数参数。由于两种实现都使用 JavaScript,因此不考虑构建交互式图表所需的时间。

使用开箱即用的解决方案时,性能提高了九倍。

我们如何使用 WebAssembly 将 Web 应用程序加速 20 倍

这是一个非常好的结果,但事实证明,它还有优化的机会。事实是大量的QC分析结果并没有被seqtk使用,因此可以将其删除。如果这样做,结果比 JS 提高了 13 倍。

我们如何使用 WebAssembly 将 Web 应用程序加速 20 倍

它是通过简单地注释掉 printf() 命令来实现的。

但这还不是全部。事实是,在这个阶段,fastq.bio通过调用不同的C函数来接收分析结果,每个函数计算自己的一组特征,从而使文件的每个片段被读取两次。

为了解决这个问题,决定将两个功能合二为一。结果,生产率提高了 20 倍。

我们如何使用 WebAssembly 将 Web 应用程序加速 20 倍

值得注意的是,如此出色的成绩并不总是能够取得。在某些情况下,性能会下降,因此值得评估每种情况。

作为结论,我们可以说 Wasm 确实提供了提高应用程序性能的机会,但您需要明智地使用它。

技能箱推荐:

来源: habr.com

添加评论