JavaScript中的并发与多线程:事件循环与工作线程

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

介绍:JavaScript 多线程的迷思与现实

JavaScript 传统上与单线程执行模型相关联。许多开发者,尤其是来自 C++ 或 Java 世界的开发者,认为这是一个限制。然而,现代 Node.js 生态系统提供了强大的工具来处理并发性,更重要的是,处理真正的多线程。在本文中,我们将解析 Event Loop 如何工作,何时使用 Worker Threads,以及如何正确构建高负载应用程序。

与每个线程拥有自己的栈并可以在不同 CPU 核心上并行执行的经典多线程不同,浏览器和 Node.js 中的 JavaScript 使用基于事件的并发模型。但随着 Node.js 中 worker_threads 模块的出现,我们获得了真正并行性的能力。

主体部分

1. Event Loop:Node.js 中并发性的核心

Event Loop 是一种机制,它允许 Node.js 执行非阻塞输入/输出(I/O)操作,尽管 JavaScript 是单线程的。它不断检查任务队列并按顺序执行它们。

Event Loop 的主要阶段:

  • Timers — 执行通过 setTimeout() 和 setInterval() 安排的回调。
  • I/O callbacks — 处理已完成的输入/输出操作。
  • Idle, prepare — Node.js 内部阶段。
  • Poll — 获取新的 I/O 事件并执行它们的回调。
  • Check — 执行 setImmediate() 的回调。
  • Close callbacks — 处理关闭事件(例如,socket.on('close', ...))。

Event Loop 工作示例:

const fs = require('fs');

console.log('程序开始');

setTimeout(() => {
    console.log('定时器触发');
}, 0);

setImmediate(() => {
    console.log('setImmediate 已执行');
});

fs.readFile(__filename, () => {
    console.log('文件已读取');
});

console.log('程序结束');

// 输出:
// 程序开始
// 程序结束
// setImmediate 已执行
// 定时器触发
// 文件已读取

重要的是要理解:Event Loop 并不会使代码变成多线程,它只是有效地在任务之间分配时间。如果一个任务占用 CPU 时间过长(例如,复杂的循环),整个 Event Loop 就会被阻塞。

2. 阻塞问题及解决方案:Worker Threads

对于 CPU 密集型任务(加密、图像处理、大数据解析),Event Loop 并不适用——它会阻塞整个服务器。这时,Worker Threads 就派上了用场。

Worker Threads 是 Node.js 的一个模块,它允许创建真正的操作系统线程。每个 worker 都有自己的 V8 实例和 Event Loop,这使得代码可以并行执行。

使用 Worker Threads 的基本示例:

// main.js
const { Worker } = require('worker_threads');

function runWorker(workerData) {
    return new Promise((resolve, reject) => {
        const worker = new Worker('./worker.js', { workerData });
        
        worker.on('message', resolve);
        worker.on('error', reject);
        worker.on('exit', (code) => {
            if (code !== 0) {
                reject(new Error(`Worker 以代码 ${code} 停止`));
            }
        });
    });
}

async function main() {
    console.log('启动 worker...');
    const result = await runWorker(42);
    console.log('结果:', result);
}

main().catch(console.error);

// worker.js
const { parentPort, workerData } = require('worker_threads');

// CPU 密集型任务
function fibonacci(n) {
    if (n < 2) return n;
    return fibonacci(n - 1) + fibonacci(n -                

博客

书籍推荐