Подтвердить что ты не робот

Распараллеливание задач в Node.js

У меня есть некоторые задачи, которые я хочу сделать в JS, которые являются ресурсоемкими. Для этого вопроса давайте предположим, что они представляют собой тяжелые вычисления, а не системный доступ. Теперь я хочу одновременно запускать задачи A, B и C и выполнять некоторую функцию D, когда это будет сделано.

асинхронная библиотека предоставляет приятные строительные леса для этого:

async.parallel([A, B, C], D);

Если то, что я делаю, это просто вычисления, тогда это все равно будет выполняться синхронно (если только библиотека не ставит задачи на разные потоки, что я ожидаю, это не так). Как сделать это на самом деле параллельным? Что обычно делается с помощью асинхронного кода, чтобы не блокировать вызывающего абонента (при работе с NodeJS)? Это начинается с дочернего процесса?

4b9b3361

Ответ 1

Как сделать это фактически параллельным?

Во-первых, вы не будете работать параллельно в одном приложении node. Приложение node работает в одном потоке, и только одно событие за раз обрабатывается циклом событий node. Даже при работе в многоядерном ящике вы не получите parallelism обработки в приложении node.

Тем не менее, вы можете получить обработку parallelism на многоядерной машине путем разметки кода в отдельные процессы node или путем создания дочернего процесса. Это, по сути, позволяет создавать несколько экземпляров самого node и взаимодействовать с этими процессами по-разному (например, stdout, процесс fork IPC-механизм). Кроме того, вы можете отделить функции (от ответственности) к своему собственному приложению/серверу node и вызвать его через RPC.

Что обычно делается с помощью асинхронного кода, чтобы не блокировать вызывающего абонента (при работе с NodeJS)? Запускает ли он дочерний процесс?

Он не запускает новый процесс. Под когда async.parallel используется в node.js, он использует process.nextTick(). А nextTick() позволяет избежать блокировки вызывающего абонента, откладывая работу на новый стек, чтобы вы могли чередовать интенсивные задачи процессора и т.д.

Короче говоря

Node не позволяет "из коробки" получить многопроцессорный concurrency. node вместо этого дает вам неблокирующий дизайн и цикл событий, который использует поток без обмена памятью. Несколько потоков не могут обмениваться данными/памятью, поэтому блокировки не нужны. node заблокирован. Один node процесс использует один поток, что делает node безопасным и мощным.

Когда вам нужно разделить работу между несколькими процессами, используйте какую-то передачу сообщений для связи с другими процессами/серверами.. IPC/RPC.


Подробнее см.

Удивительный ответ от SO на Что такое node.js... с тонны добра.

Понимание process.nextTick()

Ответ 2

Асинхронные и параллельные не то же самое. Асинхронный означает, что вам не нужно ждать синхронизации. Параллельно означает, что вы можете делать несколько вещей одновременно. Node.js является только асинхронным, но его единственным только 1 потоком. Он может работать только по одной вещи сразу. Если у вас длительное вычисление, вы должны начать другой процесс, а затем просто выполните процесс Node.js асинхронно дождаться результатов.

Для этого вы можете использовать child_process.spawn, а затем прочитать данные из stdin.

http://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options

var spawn = require('child_process').spawn;
var process2 = spawn('sh', ['./computationProgram', 'parameter'] );

process2.stderr.on('data', function (data) {
    //handle error input
});

process2.stdout.on('data', function (data) {
    //handle data results
});

Ответ 3

Имейте в виду, что I/O распараллеливается с помощью Node.js; только ваши обратные вызовы JavaScript однопоточные.

Предполагая, что вы пишете сервер, альтернативой добавлению сложности процессов нереста или форкинга является просто создание серверов без состояния node и запуск экземпляра на ядро ​​или, еще лучше, запуск многих экземпляров на своем собственном виртуализованном микросервере, Координаты входящих запросов с использованием обратного прокси-сервера или балансировки нагрузки.

Вы также можете отключить вычисление на другом сервере, возможно, MongoDB (используя MapReduce) или Hadoop.

Чтобы быть по-настоящему хардкорным, вы можете написать плагин node на С++ и иметь мелкомасштабный контроль распараллеливания кода вычислений. Ускорение от С++ может в любом случае отрицать необходимость распараллеливания.

Вы всегда можете писать код для выполнения вычислительно-интенсивных задач на другом языке, наиболее подходящем для числовых вычислений, и, например, выставлять их через API REST.

Наконец, вы могли бы запустить код на графическом процессоре, используя node-cuda или что-то подобное в зависимости от типа вычисления (не все могут быть оптимизированы для GPU).

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

Ответ 4

Совсем недавно наткнулся на parallel.js, но он, по-видимому, фактически использует многоядерные процессоры, а также имеет функции уменьшения размера карты. http://adambom.github.io/parallel.js/

Ответ 5

В зависимости от вашего варианта использования вы можете использовать что-то вроде

task.js Упрощенный интерфейс для запуска кода интенсивного процессора на всех ядрах (node.js, и веб)

Пример:

function blocking (exampleArgument) {
    // block thread
}

// turn blocking pure function into a worker task
const blockingAsync = task.wrap(blocking);

// run task on a autoscaling worker pool
blockingAsync('exampleArgumentValue').then(result => {
    // do something with result
});