笔者在 Node.js 最新的开发版本 v11.4.0 上测试该特性,目前须要添加 flag 才能引入 Worker Threads
,例如:javascript
node --experimental-worker index.js
复制代码
Worker Threads
特性是在2018年6月20日的 v10.5.0 版本引入的:html
node/CHANGELOGjava
目前该模块处于 Stability 1 - Experimental 阶段,改动会较大,不建议用于生产环境。node
模块接口git
const {
isMainThread, parentPort, workerData, threadId,
MessageChannel, MessagePort, Worker
} = require('worker_threads');
复制代码
该模块对象和类很是少,只有4个对象和3个类。github
isMainThread
:false 表示当前为 worker 线程,false
表示为主线程parentPort
: 在 worker 线程里是表示父进程的 MessagePort
类型的对象,在主线程里为 null
workerData
: 在 worker 线程里是父进程建立 worker 线程时的初始化数据,在主线程里是 undefined
threadId
: 在 worker 线程里是线程 ID,在父进程里是 0
。MessageChannel
: 包含两个已经互相可以夸线程通讯的 MessagePort
类型对象,可用于建立自定义的通讯频道,可参考样例二的实现。MessagePort
: 用于跨线程通讯的句柄,继承了 EventEmitter
,包括 close message 事件用于接收对象关闭和发送的消息,以及 close postMessage 等操做。Worker
: 主线程用于建立 worker 线程的对象类型,包含全部的 MessagePort 操做以及一些特有的子线程 meta data 操做。构造函数的第一个参数是子线程执行的入口脚本程序,第二个参数包含一些配置项,能够指定一些初始参数。 详细内容见文档在使用 cluster
和 child_process
时一般使用 SharedArrayBuffer
来实现须要多进程共享的内存。api
port.postMessage(value[, transferList])
复制代码
如今 Worker Threads 模块在 API 层不建议多线程共享内存,第一个参数 value 的值会被 clone 一份在接受消息的线程。transferList 只能传递 ArrayBuffer
或者 MessagePort
对象,传递 ArrayBuffer
会修改该 Buffer 的访问权限给接受消息的线程,传递 MessagePort
能够参考样例二。浏览器
全部跨线程消息的通讯都经过走底层的 v8 序列化实现,更具体的 Worker Threads 和 v8 多线程模型以及和浏览器的 Web Worker 标准的关系暂不展开。bash
const {
isMainThread, parentPort, workerData, threadId,
MessageChannel, MessagePort, Worker
} = require('worker_threads');
function mainThread() {
const worker = new Worker(__filename, { workerData: 0 });
worker.on('exit', code => { console.log(`main: worker stopped with exit code ${code}`); });
worker.on('message', msg => {
console.log(`main: receive ${msg}`);
worker.postMessage(msg + 1);
});
}
function workerThread() {
console.log(`worker: threadId ${threadId} start with ${__filename}`);
console.log(`worker: workerDate ${workerData}`);
parentPort.on('message', msg => {
console.log(`worker: receive ${msg}`);
if (msg === 5) { process.exit(); }
parentPort.postMessage(msg);
}),
parentPort.postMessage(workerData);
}
if (isMainThread) {
mainThread();
} else {
workerThread();
}
复制代码
输出结果:多线程
worker: threadId 1 start with /Users/azard/test/index.js
worker: workerDate 0
main: receive 0
worker: receive 1
main: receive 1
worker: receive 2
main: receive 2
worker: receive 3
main: receive 3
worker: receive 4
main: receive 4
worker: receive 5
main: receive 5
main: worker stopped with exit code 0
复制代码
const {
isMainThread, parentPort, workerData, threadId,
MessageChannel, MessagePort, Worker
} = require('worker_threads');
if (isMainThread) {
const worker1 = new Worker(__filename);
const worker2 = new Worker(__filename);
const subChannel = new MessageChannel();
worker1.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]);
worker2.postMessage({ hereIsYourPort: subChannel.port2 }, [subChannel.port2]);
} else {
parentPort.once('message', (value) => {
value.hereIsYourPort.postMessage('hello');
value.hereIsYourPort.on('message', msg => {
console.log(`thread ${threadId}: receive ${msg}`);
});
});
}
复制代码
输出:
thread 2: receive hello
thread 1: receive hello
复制代码
如今 Node.js 有了真多线程,不须要再用 cluster 或者 child_process 的多进程来处理一些问题了,相关的框架、库的模型在 Worker Threads 稳定后也能够开始进行迭代更新。