nodejs - Отправка потока из рабочего потока обратно в основной поток - PullRequest
5 голосов
/ 16 июня 2020

Я пытался разделить некоторую работу, проделанную в моей программе, в другой поток. Одна из функций должна возвращать поток в основной поток, но у меня есть следующее исключение:

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-thread-pool специально DynamicPool. А внутри пытаюсь преобразовать 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: Я знаю, что операции ввода-вывода не столь производительны в рабочих потоках, поскольку они находятся в основном потоке nodejs, но мне нужно сделать это, чтобы избежать блокировки основного потока этими операциями.

1 Ответ

2 голосов
/ 22 июня 2020

Краткая версия: вы не можете.

IP C в узле обрабатывается через какой-то черный ящик , но мы знаем, что объекты сообщений сериализуются перед отправкой и десериализуются после получения: вы не можете сериализовать Stream, потому что он основан на нижнем уровне (сокет, дескриптор файла, пользовательские функции чтения и записи и т. д. c), которые не могут быть сериализованы /deserialized.

Итак, вы вынуждены обмениваться сериализуемыми данными.

Взглянув на html-pdf Я думаю, что простой способ преобразовать вашу программу - использовать pdf.toBuffer: вместо того, чтобы пытаться чтобы отправить Stream в основной поток и прочитать его в основном потоке для получения Buffer, вы должны отправить Buffer в основной поток, а затем использовать его как есть.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...