Node.js 中的多线程方案 Worker threads

源代码: lib/worker_threads.js

node:worker_threads 模块允许使用多线程并行执行JS代码。快速引用如下:

const worker = require('node:worker_threads');

Workers (线程,下面不再注释) 在处理一些CPU密集型操作上非常有用。 但是对IO密集型操作则不适用。这是因为Node.js自带的IO多线程异步(Event loop)能力已经比 Workers 要更加强大。

不同于child_process(子线程) 或者 cluster(集群), worker_threads 可以直接共享内存。 他们可以通过传递 ArrayBuffer 或者 SharedArrayBuffer 实例来实施共享。

const {
  Worker, isMainThread, parentPort, workerData
} = require('node:worker_threads');

if (isMainThread) {
  module.exports = function parseJSAsync(script) {
    return new Promise((resolve, reject) => {
      const worker = new Worker(__filename, {
        workerData: script
      });
      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 { parse } = require('some-js-parsing-library');
  const script = workerData;
  parentPort.postMessage(parse(script));
}

上面的例子为每一个 parseJSAsync() 调用部署了一个 Worker thread 去做 parse()逻辑。在实际情况当中,代码逻辑应当使用 Worker 池来缓存起来Worker,而不是每次调用都进行创建。否则,过度创建Worker的负面代价,就有可能超过Worker的使用带来的好处了。

在写一个Worker池时,使用 AsyncResource API 来通知诊断工具 (e.g. 提供一个异步调用的堆栈) 有关于任务和产出结果有关的相关性。 参考"在Worker thread 池中使用 AsyncResource" 里的 async_hooks 部分文档,里面有一个相关的实现实例。

Worker threads 默认继承无进程指定(non-process-specific)选项。参考 Worker 构建函数选项 来了解如何定制Worker跟线程的特性,特别是 argv 和 execArgv 选项。

worker.getEnvironmentData(key)

  • key <any> 所有任意的、可复制的JS值,用法类似一个 <Map> key.
  • Returns: <any>

在一个 worker thread 内, worker.getEnvironmentData() 会返回一个在创建线程时,调用的 worker.setEnvironmentData() 所传入的值的克隆。每一个新建的 Worker 都会收到一份这个克隆。

const {
  Worker,
  isMainThread,
  setEnvironmentData,
  getEnvironmentData,
} = require('node:worker_threads');

if (isMainThread) {
  setEnvironmentData('Hello', 'World!');
  const worker = new Worker(__filename);
} else {
  console.log(getEnvironmentData('Hello'));  // Prints 'World!'.
}

worker.isMainThread

如果不是在一个Worker线程中,返回True。

const { Worker, isMainThread } = require('node:worker_threads');

if (isMainThread) {
  // This re-loads the current file inside a Worker instance.
  new Worker(__filename);
} else {
  console.log('Inside Worker!');
  console.log(isMainThread);  // Prints 'false'.
}

worker.markAsUntransferable(object)

标志一个Object是不可在Worker间传输的。如果被标记的Object出现在 port.postMessage() 的传输列表中,它将会被忽略掉(此处存疑,可能是赋值而不是直接传输的意思)。

特别是,这对一些在发送端只能被复制而不是直接传送走的Objects是有用的。 举个例子, Node.js在自己的  Buffer pool  中用这个标记了 ArrayBuffers。

此操作不可回退。

const { MessageChannel, markAsUntransferable } = require('node:worker_threads');

const pooledBuffer = new ArrayBuffer(8);
const typedArray1 = new Uint8Array(pooledBuffer);
const typedArray2 = new Float64Array(pooledBuffer);

markAsUntransferable(pooledBuffer);

const { port1 } = new MessageChannel();
port1.postMessage(typedArray1, [ typedArray1.buffer ]);

// The following line prints the contents of typedArray1 -- it still owns
// its memory and has been cloned, not transferred. Without
// `markAsUntransferable()`, this would print an empty Uint8Array.
// typedArray2 is intact as well.
console.log(typedArray1);
console.log(typedArray2);

在浏览器中没有对应的API,只有nodejs后端中有。

后面都是一些api,再参考:Worker threads | Node.js v18.1.0 Documentation

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值