本文档详细介绍了 Node.js Worker Threads 架构,解释了 Node.js 如何通过隔离的线程实现并行 JavaScript 执行。它涵盖了 worker 线程的创建方式、它们之间的通信方式以及它们的生命周期管理。有关用于创建和与 worker 线程交互的模块 API 的信息,请参阅 worker_threads 模块的文档。
Worker 线程提供了一种通过在单独的线程中运行代码来并行执行 JavaScript 的方法。与创建单独进程的 cluster 模块不同,worker 线程共享同一个进程,但拥有自己隔离的 JavaScript 执行环境。
Node.js 中的 Worker 线程的设计遵循以下原则:
Worker 线程的主要优势
| 功能 | 描述 |
|---|---|
| 内存共享 | 通过 SharedArrayBuffer 高效共享内存。 |
| 较低的开销 | 比创建单独进程的成本更低。 |
| 并行执行 | 利用多个 CPU 核心执行 JavaScript。 |
| 独立的崩溃处理 | Worker 中的错误不会导致主应用程序崩溃。 |
来源:src/node_worker.h28-137 src/node_worker.cc1-50
Worker 线程架构由几个关键组件组成,这些组件相互作用,在同一进程中创建和管理独立的 JavaScript 执行环境。
来源:src/node_worker.h28-137 src/node_worker.cc50-146 src/node.cc358-405
The Worker 类是 worker 线程系统的核心组件。它充当主线程和子线程之间的桥梁。
主线程中的每个 Worker 实例负责管理:
来源:src/node_worker.h28-137 src/node_worker.cc50-104
The WorkerThreadData 类管理仅在 worker 线程运行时与该线程本身相关的数据。它负责:
uv_loop_t)。创建新 worker 时,会经历一个复杂的初始化过程,以创建一个隔离的 JavaScript 环境。
该过程包括以下步骤:
Worker 构造:
Worker 实例。线程初始化:
环境设置:
IsolateData 实例。Environment。代码执行:
来源:src/node_worker.cc144-339 src/node_worker.cc498-624
每个 worker 线程都有自己的 V8 隔离环境,它提供了一个独立的 JavaScript 执行环境。这是 worker 架构的关键部分。
Worker 隔离环境创建的重要方面:
资源限制:Worker 可以为以下方面设置自定义内存限制:
隔离环境配置:
Worker 上下文关联:
set_worker_context() 将 worker 与其隔离环境数据相关联。来源:src/node_worker.cc144-227 src/api/environment.cc303-345
Worker 通过消息端口与主线程和其他 worker 进行通信。通信模型使用显式的消息传递,而不是共享内存(尽管 SharedArrayBuffer 可用于共享内存)。
创建 worker 时:
这会在主线程和 worker 线程之间建立一个双向通信通道。消息端口允许结构化克隆 JavaScript 对象或在线程之间传递某些对象。
来源:src/node_worker.cc73-83 src/node_messaging.cc
Worker 线程可以配置各种资源限制,以控制内存使用量并防止单个 worker 消耗过多资源。
Worker 支持多种类型的内存限制:
这些限制在 worker 创建期间应用,可以根据 worker 的具体需求进行自定义,以优化资源使用。
Worker 实现了类似于其他 Node.js handle 的引用计数机制,允许控制 worker 是否保持事件循环的活动状态。
在底层,这由 Worker 类中的 has_ref_ 属性管理,并传递给 libuv。
来源:src/node_worker.h70-81 src/node_worker.cc104-143
Worker 线程的生命周期包括创建、执行和终止阶段。
Worker 可以通过几种方式终止:
worker.terminate() 方法。process.exit()。Worker 终止时,会进行清理过程:
来源:src/node_worker.cc625-734 src/node_worker.cc786-829
Node.js Worker 线程实现了各种机制来确保线程安全:
| 机制 | 描述 |
|---|---|
| 互斥锁 | 保护对共享数据结构的访问。 |
| 消息传递 | 显式通信,而非共享状态。 |
| 隔离的堆 | 每个线程都有自己的 JavaScript 堆。 |
| 线程本地存储 | 环境和隔离环境数据是线程本地的。 |
The Worker 类本身使用互斥锁来保护可能从主线程和 worker 线程访问的字段。
来源:src/node_worker.h97-99 src/node_worker.cc106-208
Worker 线程通过 inspector 协议支持调试。创建 worker 时,可以为其创建一个 InspectorParentHandle。
这允许调试工具连接并调试单个 worker 线程。
来源: src/node_worker.cc92-96 src/api/environment.cc389-465
Node.js Worker Threads 架构提供了一种在同一进程内创建隔离的 V8 环境来并行执行 JavaScript 代码的方式。该设计平衡了隔离的安全性与实用的高效通信机制。
关键架构方面包括:
这种架构使 Node.js 应用程序能够有效地利用多核系统,同时保持了 JavaScript 开发人员熟悉的每个 Worker 内部的单线程执行模型。