worker_threads
不同于 child_process 、cluster 是创建子进程,worker_threads 是创建线程,它们共享进程所有的内存,因此相比多进程可以节省内存。
多线程对于执行 CPU 密集型 JavaScript 操作能起到并行效果,而对I/O密集型任务没有帮助。
worker_threads 的用法和浏览器端 Worker 相似但不同。
下面的代码导出一个模块,模块内创建线程来处理任务,并异步返回内容
js
const {
Worker,
isMainThread,
parentPort,
workerData,
} = require('node:worker_threads')
if (isMainThread) {
module.exports = function clonseJSAsync(obj) {
return new Promise((resolve, reject) => {
const worker = new Worker(__filename, {
workerData: obj,
})
worker.on('message', resolve)
worker.on('error', reject)
worker.on('exit', (code) => {
if (code !== 0)
reject(new Error(`Worker stopped with exit code ${code}`))
})
})
}
} else {
const deepClone = (obj) => JSON.parse(JSON.stringify(obj))
const obj = workerData
parentPort.postMessage(deepClone(obj))
}
模块的作用是简单地深拷贝对象。
使用这个模块,对比不使用 worker_threads 进行深拷贝对象的耗时
js
const threadsClone = require('./worker')
const data = require('./enemy')
console.time('single clone')
for (let i = 0; i < 100; i++) {
JSON.parse(JSON.stringify(data))
}
console.timeEnd('single clone')
console.time('threads clone')
const promises = []
for (let i = 0; i < 100; i++) {
promises.push(threadsClone(data))
}
Promise.all(promises).then(() => {
console.timeEnd('threads clone')
})
在4核心电脑上,运行输出如下:
single clone: 37.17ms
threads clone: 1.890s
显然,创建 Worker 的开销超过了多线程的收益。
实际使用中会使用线程池,复用创建的固定数量的Workers,来完成任务。即通过编程的方式实现 cluster
那样进行多线程的负载均衡。