首页 > 解决方案 > nodejs - 将流从工作线程发送回主线程

问题描述

我一直试图将在我的程序中完成的一些工作分开在不同的线程中。其中一个函数需要将流返回到主线程,但我遇到以下异常:

Error
    at MessagePort.<anonymous> ([worker eval]:12:16)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
From previous event:
    at PoolWorker.work (node_modules/node-worker-threads-pool/src/pool-worker.js:22:12)
    at DynamicPool.runTask (node_modules/node-worker-threads-pool/src/pool.js:110:47)
    at DynamicPool.exec (node_modules/node-worker-threads-pool/src/dynamic-pool.js:51:17)
    at renderToPdf (src/modules/templates/render2.js:27:14)
    at Context.<anonymous> (test/modules/templates/render.test.js:185:68)

我试图构建一个最小的例子来重现我想要实现的目标。基本上,我需要的是向主线程发回一个可读流。在这个例子中,我也有一个例外:

为了有一个工作线程池,我专门使用库node-worker-threads-pool动态池。在里面我正在尝试转换html为PDF。但我需要以某种方式将流返回到主线程。

const os = require('os');
const { DynamicPool } = require('node-worker-threads-pool');

const Pool = new DynamicPool(os.cpus().length);

async function convertToPDF(html) {
  return await Pool.exec({
    task: function() {
      const Promise = require('bluebird');
      const pdf = require('html-pdf');

      const { html } = this.workerData;

      const htmlToPdf = (html, renderOptions) => {
        const options = {
          format: 'Letter',
        };
        return pdf.create(html, Object.assign(options, renderOptions || {}));
      };

      return Promise.fromNode((cb) => htmlToPdf(html, {}).toStream(cb));
    },
    workerData: {
      html,
    },
  });
}

convertToPDF('<div>Hello World!</div>')
  .then((resp) => console.log('resp', resp))
  .catch((err) => console.error('err', err));
err DataCloneError: function() {
    if (this.autoClose) {
      this.destroy();
    }
  } could not be cloned.
    at MessagePort.<anonymous> ([worker eval]:12:16)
    at processTicksAndRejections (internal/process/task_queues.js:97:5)

您知道我该如何实现这一目标吗?

PS:我知道 IO 操作在工作线程中的性能不如它们在 nodejs 主线程中,但我需要这样做以避免这些操作锁定主线程。

标签: node.jsmultithreading

解决方案


简短版:你不能。

node 中的 IPC 是通过一些黑盒处理的,但是我们知道消息对象在发送之前被序列化,并且在收到后被反序列化:你不能序列化 aStream因为它基于底层级别(套接字、文件描述符、自定义读取并编写无法序列化/反序列化的函数等)。

所以你不得不交换可序列化的数据。

看一下html-pdf我认为转换程序的一种简单方法是使用pdf.toBuffer:与其尝试将 a 发送Stream到主线程并在主线程中读取它以获得 a Buffer,不如将 a 发送Buffer到主线程而不是按原样使用它。

希望这可以帮助。


推荐阅读