何时用
Node 单线程跑 JS——CPU 密集任务(图像处理、加密、复杂计算)会阻塞事件循环,所有请求都等。
// ❌ 阻塞
function fibonacci(n) {
if (n < 2) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
server.on('request', () => {
fibonacci(40); // 阻塞 1+ 秒
});
解决方案优先级:
- 算法优化(最有效)
- 拆任务(每几 ms 让出循环)
- worker_threads(同进程多线程,下面讲)
- child_process / cluster(多进程,更重)
基础
// main.js
import { Worker } from 'worker_threads';
const worker = new Worker('./worker.js');
worker.on('message', result => {
console.log('Result:', result);
});
worker.postMessage({ task: 'fib', n: 40 });
// worker.js
import { parentPort } from 'worker_threads';
function fibonacci(n) {
if (n < 2) return n;
return fibonacci(n-1) + fibonacci(n-2);
}
parentPort.on('message', msg => {
if (msg.task === 'fib') {
const result = fibonacci(msg.n);
parentPort.postMessage(result);
}
});
内联代码(不用单独文件)
import { Worker } from 'worker_threads';
const worker = new Worker(`
const { parentPort } = require('worker_threads');
parentPort.on('message', n => {
let result = 0;
for (let i = 0; i < n; i++) result += i;
parentPort.postMessage(result);
});
`, { eval: true });
worker.postMessage(1000000);
worker.on('message', console.log);
Promise 包装
实战中常包成 Promise:
function runInWorker(task) {
return new Promise((resolve, reject) => {
const worker = new Worker('./worker.js');
worker.on('message', result => {
resolve(result);
worker.terminate();
});
worker.on('error', reject);
worker.postMessage(task);
});
}
const result = await runInWorker({ task: 'heavy-compute', data: [...] });
数据传递
Worker 间通信通过 postMessage——数据被结构化克隆(深拷贝):
worker.postMessage({ name: 'Alice', tags: ['a', 'b'] });
⚠ 不能传函数 / Symbol / DOM。
大数据用 Transferable(零拷贝)
const buffer = new ArrayBuffer(100 * 1024 * 1024); // 100 MB
worker.postMessage(buffer, [buffer]);
// 第二参数 = transferable list
// → buffer 所有权转给 worker,主线程不能再访问
SharedArrayBuffer(线程共享内存)
const sab = new SharedArrayBuffer(4); // 4 字节
const view = new Int32Array(sab);
worker.postMessage(sab); // 不复制,共享
// 两端都能读写 view
view[0] = 42;
⚠ 需要正确用 Atomics 处理同步——否则有数据竞争。
线程池:worker pool
每次新建 worker 慢——生产用线程池:
import { Worker } from 'worker_threads';
class WorkerPool {
constructor(size, script) {
this.workers = Array.from({ length: size }, () => new Worker(script));
this.queue = [];
this.idle = [...this.workers];
}
run(task) {
return new Promise((resolve, reject) => {
const job = { task, resolve, reject };
const w = this.idle.pop();
if (w) this.assign(w, job);
else this.queue.push(job);
});
}
assign(worker, job) {
worker.once('message', result => {
job.resolve(result);
const next = this.queue.shift();
if (next) this.assign(worker, next);
else this.idle.push(worker);
});
worker.postMessage(job.task);
}
}
const pool = new WorkerPool(4, './worker.js');
const results = await Promise.all(tasks.map(t => pool.run(t)));
或用现成库:piscina(最流行):
import Piscina from 'piscina';
const pool = new Piscina({ filename: './worker.js' });
const result = await pool.run({ a: 1, b: 2 });
worker_threads vs child_process vs cluster
| 共享内存 | 启动开销 | 通信开销 | 适合 | |
|---|---|---|---|---|
| worker_threads | ★(同进程) | 低 | 极低 | CPU 密集 + 同代码 |
| child_process | ✗ | 中 | 高(IPC) | 跑外部命令 / 独立逻辑 |
| cluster | ✗ | 中 | 高 | 利用多核跑同一 HTTP 服务 |
坑
- worker 启动比想象的慢(几十 ms)—— 频繁短任务用线程池
- worker 不共享主进程内存——除非 SharedArrayBuffer
- worker 里不能用 process.exit(用
parentPort.close()或退出 worker) - 异常未捕获 → worker 退出 + main
error事件
下一篇:cluster 多进程。