Chrome 70 中的 WebAssembly 线程现已可试用

在初始试用阶段,Chrome 70 中已提供 WebAssembly 线程支持。

Alex Danilo

WebAssembly (Wasm) 支持对使用 C++ 和其他语言编写的代码进行编译 供您在网络上运行。原生应用的一项非常实用的功能是能够使用线程,线程是并行计算的基本功能。大多数 C C++开发者非常熟悉 pthreads, 用于在应用中进行线程管理的标准化 API。

WebAssembly 社区群组一直致力于将线程引入 Web 以实现真正的多线程应用。作为这项工作的一部分,V8 在 WebAssembly 引擎中实现了对线程的必要支持,可通过源试用版获得。源试用 让开发者可以在新的 Web 功能全面投入使用之前,对它们进行试验 标准化。这样一来,我们就可以从大胆的开发者那里收集真实反馈,这对验证和改进新功能至关重要。

Chrome 70 版本支持 WebAssembly 线程,我们建议 有兴趣的开发者开始使用这些功能,并向我们提供反馈。

线程?工人呢?

自 2012 年以来,浏览器在 Chrome 4 中一直支持通过 Web Worker 实现并行处理;在 “在主线程上”这样的词语是很正常的等。但是, 工作器不会在它们之间共享可变数据,而是依赖于 以及通过消息传递进行通讯事实上,Chrome 会为每个 isolate 分配一个新的 V8 引擎。隔离容器既不共享已编译的代码也不共享 JavaScript 对象,因此它们无法共享可变数据(如 pthread)。

另一方面,WebAssembly 线程是可以共享同一 Wasm 的线程 内存。共享内存的底层存储是通过 SharedArrayBuffer 实现的,这是一种 JavaScript 基元,允许在多个工作器之间同时共享单个 ArrayBuffer 的内容。每个 WebAssembly 线程都在 Web Worker 中运行,但由于它们共享 Wasm 内存,因此其工作方式与在原生平台上的工作方式非常相似。这意味着,使用 Wasm 线程的应用负责管理对共享内存的访问,就像在任何传统线程应用中一样。目前有很多使用 C 或 C++ 编写的代码库 使用 pthreads,这些线程可编译到 Wasm 并在 true 下运行 线程模式,让更多核心可以同时处理相同的数据。

一个简单示例

下面是一个简单的“C”示例使用线程的程序

#include <pthread.h>
#include <stdio.h>

// Calculate Fibonacci numbers shared function
int fibonacci(int iterations) {
    int     val = 1;
    int     last = 0;

    if (iterations == 0) {
        return 0;
    }
    for (int i = 1; i < iterations; i++) {
        int     seq;

        seq = val + last;
        last = val;
        val = seq;
    }
    return val;
}
// Start function for the background thread
void *bg_func(void *arg) {
    int     *iter = (void *)arg;

    *iter = fibonacci(*iter);
    return arg;
}
// Foreground thread and main entry point
int main(int argc, char *argv[]) {
    int         fg_val = 54;
    int         bg_val = 42;
    pthread_t   bg_thread;

    // Create the background thread
    if (pthread_create(&bg_thread, NULL, bg_func, &bg_val)) {
        perror("Thread create failed");
        return 1;
    }
    // Calculate on the foreground thread
    fg_val = fibonacci(fg_val);
    // Wait for background thread to finish
    if (pthread_join(bg_thread, NULL)) {
        perror("Thread join failed");
        return 2;
    }
    // Show the result from background and foreground threads
    printf("Fib(42) is %d, Fib(6 * 9) is %d\n", bg_val, fg_val);

    return 0;
}

该代码以 main() 函数开头,该函数声明了 2 个变量 fg_valbg_val。还有一个函数称为 fibonacci(): 线程。main() 函数使用 pthread_create() 创建一个后台线程,该线程的任务是计算与 bg_val 变量的值对应的斐波那契数序列值。与此同时,在前台线程中运行的 main() 函数会为 fg_val 变量计算该值。部署 后台线程已完成运行,系统会输出结果。

针对线程支持进行编译

首先,您应安装 emscripten SDK,最好是 1.38.11 或更高版本。要使用 已启用的线程 要在浏览器中运行,我们需要向 emscripten emcc 编译器。我们的命令行如下所示:

emcc -O2 -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=2 -o test.js test.c

命令行参数“-s USE_PTHREADS=1”开启线程支持 已编译的 WebAssembly 模块和参数“-s PTHREAD_POOL_SIZE=2” 指示编译器生成由两 (2) 个线程组成的池。

运行程序时,程序会在后台加载 WebAssembly 模块,为线程池中的每个线程创建一个 Web Worker,并与每个 worker 共享该模块(在本例中为 2),每当调用 pthread_create() 时,这些 worker 都会被使用。每个 Worker 都会将 Wasm 模块,以便它们能够进行协作。V8 7.0 中的最新变更共享了在工作器之间传递的 Wasm 模块的已编译原生代码,这使得即使非常大型的应用也能扩展到许多工作器。请注意,请务必确保线程池大小等于应用所需的线程数量上限,否则线程创建可能会失败。同时,如果线程池大小过大,您将创建不必要的 Web Worker,这些 Worker 除了占用内存外,什么也不会做。

如何试用

如需快速测试我们的 WebAssembly 模块,最快的方法是在 Chrome 70 及更高版本中开启实验性 WebAssembly 线程支持。在浏览器中前往网址 about://flags,如下所示:

Chrome flag 页面

接下来,找到实验性 WebAssembly 线程设置,该设置如下所示:

WebAssembly 线程设置

如下所示,将设置更改为已启用,然后重启浏览器。

已启用 WebAssembly 线程设置

浏览器重启后,我们可以尝试使用仅包含以下内容的最小 HTML 页面加载线程化 WebAssembly 模块:

<!DOCTYPE html>
<html>
  <title>Threads test</title>
  <body>
    <script src="test.js"></script>
  </body>
</html>

如需试用此页面,您需要运行某种形式的 Web 服务器,并从浏览器加载该服务器。这会使 WebAssembly 模块加载并运行。开场白 DevTools 会显示运行的输出,您应该会看到类似 控制台中显示的以下输出图片:

斐波那契程序在控制台上的输出

包含线程的 WebAssembly 程序已成功执行!我们建议 您可以按照上述步骤试用自己的线程式应用。

通过源试用在现场进行测试

在浏览器中启用实验性标记来试用线程是 但如果您想在测试环境中测试自己的应用 可以使用所谓的 源试用

通过源试用,您可以 与您的网域绑定的测试令牌。然后,您可以部署应用,并希望它能在支持您要测试的功能的浏览器(在本例中为 Chrome 70 及更高版本)中正常运行。如需获取自己的令牌以运行来源试用,请使用此处的表单提交申请。

我们使用源试用令牌托管了上面的简单示例,因此您可以 亲自试用 而无需构建任何内容。

如果你想了解并行运行的 4 个线程对 ASCII 图谱有何用处,那么 你必须接受 请观看此演示

向我们提供反馈

WebAssembly 线程是一项非常实用的新基元,可用于将应用移植到 Web 平台。现在,您可以在 WebAssembly 环境中运行需要 pthreads 支持的 C 和 C++ 应用和库。

我们正在向试用此功能的开发者寻求反馈,这有助于 为标准化过程提供信息,并验证其实用性。最佳 发送反馈的方式是 报告问题并/或获取 标准化 代码生成 WebAssembly 社区群组