当前位置: 首页 > news >正文

node.js之---子线程(child_process)模块

为什么需要子线程(child_process)模块

Worker Threads 的基本概念

如何使用 Worker Threads

Worker Threads 的性能

Worker 线程的优势和限制

进阶用法:共享内存

为什么需要子线程(child_process)模块

在 Node.js 中,Worker Threads 模块worker_threads)提供了一种在 Node.js 单线程 中使用多线程的方式,从而能够更高效地处理计算密集型任务,避免阻塞主线程(事件循环)。这是 Node.js 中引入的一种并发处理机制,旨在提高性能,尤其是在需要大量计算的情况下。

Node.js 默认是单线程的,它通过事件循环来处理异步操作。虽然 Node.js 可以在后台异步执行 I/O 操作(如文件读取、数据库查询等),但它的事件循环在处理计算密集型任务时会被阻塞。这意味着长时间运行的 CPU 密集型任务(如大型数据处理或算法计算)可能会阻塞事件循环,从而影响整个应用的响应能力。

为了克服这个问题,Node.js 引入了 Worker Threads 模块,它允许你在单个进程中创建多个线程,每个线程都拥有自己的执行上下文,并可以并行地处理任务。

Worker Threads 的基本概念

  • 主线程(Main thread):主线程是 Node.js 应用的默认执行环境。所有的 I/O 操作和事件循环都在主线程中进行。
  • Worker 线程(Worker threads):每个 Worker 线程拥有自己的事件循环和内存空间。它们与主线程并行运行,能够处理独立的任务。

如何使用 Worker Threads

要使用 Worker Threads,首先需要引入 worker_threads 模块。每个 Worker 线程都可以通过 Worker 类来创建,主线程和 Worker 线程之间的通信是通过 消息传递 实现的。主线程可以向 Worker 线程发送消息,Worker 线程也可以向主线程发送结果。

Worker Threads 的核心 API
  • worker_threads.Worker: 用于创建一个新的 Worker 线程。
  • worker_threads.isMainThread: 一个布尔值,用来判断当前代码是否在主线程中执行。
  • worker_threads.parentPort: 主线程和 Worker 线程之间的通信通道。
  • worker_threads.workerData: 允许向 Worker 线程传递数据。
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');if (isMainThread) {// 主线程代码console.log('主线程正在运行');// 创建 Worker 线程const worker = new Worker(__filename, {workerData: { start: 1, end: 5 }});// 监听 Worker 线程返回的消息worker.on('message', (result) => {console.log(`主线程收到结果:${result}`);});worker.on('error', (err) => {console.error('Worker 线程发生错误:', err);});worker.on('exit', (code) => {if (code !== 0) {console.error(`Worker 线程退出时的错误代码: ${code}`);}});
} else {// Worker 线程代码console.log('Worker 线程正在运行');const { start, end } = workerData;// 执行任务并将结果返回给主线程let result = 0;for (let i = start; i <= end; i++) {result += i;}parentPort.postMessage(result);  // 向主线程发送结果
}

Worker Threads 的性能

  • 线程池大小:默认情况下,Worker Threads 模块使用系统的线程池。每个 Worker 线程在独立的 CPU 核心上运行,理论上可以并行执行多个计算任务。
  • 内存隔离:每个 Worker 线程拥有独立的内存空间和执行上下文,不会与其他线程共享数据,因此可以避免传统多线程编程中的竞态条件问题。
  • 开销:每个 Worker 线程都需要一定的资源开销(内存、启动时间等),所以要谨慎创建过多的 Worker 线程。

Worker 线程的优势和限制

优点

  • 避免阻塞:Worker 线程可以并行处理计算密集型任务,不会阻塞主线程的事件循环。
  • 内存隔离:每个 Worker 线程有独立的内存空间,避免了共享内存带来的问题。
  • 更好的多核利用:可以利用多核 CPU 来并行处理任务,充分发挥硬件性能。

限制

  • 消息传递开销:线程间的通信是基于消息传递的,这可能会引入一定的延迟,尤其是在需要频繁交互的场景下。
  • 内存限制:每个 Worker 线程都需要占用一定的内存和资源,创建大量的 Worker 线程可能导致内存消耗过高。
  • 无法共享内存:Worker 线程之间没有共享内存空间,虽然可以通过 SharedArrayBuffer 实现共享内存,但这需要额外的管理和同步机制。

进阶用法:共享内存

虽然 Worker 线程之间没有直接的内存共享,但可以通过 SharedArrayBuffer 实现内存共享。SharedArrayBuffer 是一种允许在多个线程之间共享内存的结构,适用于需要高效交换大量数据的场景。

const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
const { SharedArrayBuffer, Int32Array } = require('buffer');if (isMainThread) {const sharedBuffer = new SharedArrayBuffer(4 * Int32Array.BYTES_PER_ELEMENT);const sharedArray = new Int32Array(sharedBuffer);// 将共享内存传递给 Worker 线程const worker = new Worker(__filename, { workerData: sharedBuffer });worker.on('message', () => {console.log(`Main Thread: Shared memory content: ${sharedArray[0]}`);});
} else {const sharedArray = new Int32Array(workerData);// 修改共享内存sharedArray[0] = 42;parentPort.postMessage('done');
}

在这个例子中,SharedArrayBuffer 允许主线程和 Worker 线程之间共享内存。通过 Int32Array 视图访问和修改这块内存。


http://www.mrgr.cn/news/82508.html

相关文章:

  • Go语言的 的并发编程(Concurrency)核心知识
  • IDEA 撤销 merge 操作(详解)
  • 【vim】vim常用操作总结
  • Elasticsearch DSL版
  • 数字图像处理 三 空间滤波
  • python线程与C++线程之间的区别
  • 【大模型】7 天 AI 大模型学习
  • node.js之---CommonJS 模块
  • LLVM防忘录
  • 上升沿下降沿递增
  • VSCode下配置Blazor环境 断点调试Blazor项目
  • 今日复盘103周五(189)
  • ROS2软件架构全面解析-学习如何设计通信中间件框架
  • Java实现UDP与TCP应用程序
  • 《Spring Framework实战》1:Spring简介
  • NetCore开发的文件下载器,国外文件地址可下载
  • xxljob
  • CPU缓存架构详解高性能内存队列Disruptor实战
  • 黑马Java面试教程_P10_设计模式
  • 无刷直流电机偏移角度
  • Python基础语法(上)
  • CDP集成Hudi实战-spark shell
  • halcon三维点云数据处理(五)创建代表工具和机器人底座的3D模型
  • STM32-笔记34-4G遥控灯
  • C++ hashtable
  • node.js之---EventEmitter 类