Как написать код Node.js, использующий потоки?

Итак, это мое понимание того, как работает узел:

  • Один поток, в котором выполняется весь ваш код JS.
  • IO/сетевой вызов использует пулы потоков за сценой. (используя libuv, который является библиотекой C++)
  • После завершения операции ввода-вывода ее обратный вызов помещается в очередь обратного вызова, и обратный вызов может быть получен циклом обработки событий в следующем такте.

Я хочу понять, как написать код, который может использовать системные потоки? Должен ли я написать библиотеку на C/C++ и предоставить для этого привязки Javascript?

Допустим, у меня есть некоторая операция/функция, которая не требует ввода-вывода, но интенсивно использует ЦП, поэтому я хотел бы запустить ее в нескольких потоках. Как бы я сделал это в Node?


person Jatin    schedule 06.07.2016    source источник


Ответы (3)


Насколько я понимаю, это невозможно сделать с помощью Node. Можно, конечно, написать программу на другом языке и запрограммировать некоторые привязки, но сам Node не поддерживает многопоточность. Вместо этого вы можете использовать мультипрограммирование: запустите несколько экземпляров вашей программы Node и обменивайтесь сообщениями через HTTP. Затем ваша операционная система будет обрабатывать распределение экземпляров вашей программы на разных ядрах ЦП.

person Daniel Diekmeier    schedule 06.07.2016

Node использует libuv, реализующий пул потоков. Прочтите здесь, чтобы хорошее объяснение. Вишневый выбор из статьи

Библиотека libuv поддерживает пул потоков, который используется node.js для выполнения длительных операций в фоновом режиме, не блокируя основной поток. По сути, глубоко внутри node.js основан на потоках, нравится вам это или нет.

Так что, возможно, исследуйте, как это делает libuv и как она взаимодействует с Node, и основывайте на этом свой собственный подход?

Этот ответ хорошо объясняет, показывает часть кода libuv и ссылается на другой отличная статья о libuv.

person Philip O'Brien    schedule 06.07.2016

Узел, являющийся однопоточным, является распространенным заблуждением. Правда гораздо сложнее. Хотя цикл событий узла является однопоточным, некоторые функции, включенные в стандартную библиотеку Node, не являются однопоточными.

Некоторые из функций, включенных в Node, которые мы запускаем, выполняются вне цикла событий и, следовательно, вне этого отдельного потока.

Таким образом, большая часть кода, который мы пишем в Node, не выполняется полностью внутри одного потока.

Вы можете проверить это на себе, написав код, который дает вам реальное доказательство того, что не весь Node действительно однопоточный, путем реализации функции pbkdf2 из модуля crypto.

Вы можете сравнить, сколько времени занимает выполнение функции pbkdf2, чтобы получить представление о том, как многопоточность и пулы потоков на самом деле работают на вашем компьютере. Таким образом, вы можете создавать различные pbkdf2 функции для представления потоков. Функция будет выполнять некоторую дорогостоящую работу, и вы можете протестировать ее и использовать для определения того, является ли Node однопоточным, например:

const crypto = require('crypto');

const start = Date.now();
crypto.pbkdf2('a', 'b', 100000, 512, 'sha512', () => {
  console.log('1:', Date.now() - start);
});

Для запуска этой функции требуется довольно много времени, около 1 секунды в большинстве MacBook Pro середины 2015 года.

Таким образом, приведенная выше функция обратного вызова вычисляет хэш, который опять же с машиной, указанной выше, должен выполняться не более 1 секунды, но то, что делает функция, не так важно, как время, необходимое для ее выполнения на вашей машине.

Вы можете добавить дополнительные вызовы функций для представления большего количества потоков, а также настроить размер пула потоков в пуле потоков вашей машины, например process.env.UV_THREADPOOL_SIZE = 2;.

person Daniel    schedule 19.02.2019