20

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

async library обеспечивает хорошие подмостки для этого:

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

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

+3

Я не действительно убедитесь, что вы должны использовать 'async.js'. JavaScript не имеет многопоточности, кроме WebWorkers. Я не думаю, что 'parallel()' на самом деле означает, что он выполняется многопоточным способом, он просто определяет зависимость между процессами. – Halcyon

+0

Я думаю, что js является одиночным threadd –

+1

Я не думаю, что это работает в nodejs (я думаю, вам нужно несколько процессов), но все равно проверьте это: http://adambom.github.io/parallel.js/ –

ответ

29

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

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

При этом вы можете получить параллелизм обработки на многоядерной машине via forking the code into separate node processes или by spawning child process. Это, по сути, позволяет создавать несколько экземпляров самого узла и взаимодействовать с этими процессами по-разному (например, stdout, процесс fork IPC-механизм). Кроме того, вы можете отделить функции (от ответственности) до своего собственного приложения/сервера узла и вызвать его через RPC.

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

Это не новый процесс. Underneath, when async.parallel is used in node.js, используется process.nextTick(). И nextTick() позволяет избежать блокировки вызывающего откладывая работу на новый стек, так что вы можете чередовать ресурсоемкие задачи и т.д.

Длинная короткая история

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

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


подробнее см:

Удивительный ответ от SO на What is Node.js ... с тоннами благости.

Understanding process.nextTick()

+0

«цикл событий, который использует потоки без обмена памятью». Я не совсем понимаю, что это значит. Можете ли вы ссылаться на какое-то хорошее объяснение? –

+0

Да, это легко понять неправильно. Спасибо, я уточню. –

11

Асинхронные и параллельные не то же самое. Асинхронный означает, что вам не нужно ждать синхронизации. Параллельно означает, что вы можете делать несколько вещей одновременно. 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 
}); 
+0

Право. Так порождает дочерний процесс то, что делают такие вещи, как функции, которые Node обеспечивает для взаимодействия с файловой системой и еще чего-то?Я предполагаю, что Node асинхронен по какой-то причине и больше не видит возможности параллелизма. Хотя мне ясно, что не все асинхронные вещи параллельны, некоторые вещи должны быть. Мой вопрос в том, какие вещи и как они достигают «делающих вещи, не блокируя дальнейшее выполнение JS». –

+1

@JeroenDeDauw Функции, которые узел предоставляет для доступа к файловой системе, в конечном счете взаимодействуют с ядром ОС через C. Для чтения() файла в C используется системный вызов # 3 в ядре linux. Ядро на самом деле не работает как процесс, но для этого обсуждения он хорошо себя чувствует. Приложение может выполнять неблокирующие чтения с использованием функции чтения libc() в сочетании с select() для проведения опроса. Я предполагаю, что это то, что делает узел. Узел является асинхронным, поэтому вашей программе не нужно ждать ввода-вывода. IO работает медленно, ваш процессор может обслуживать множество запросов в то время, которое требуется для ожидания ввода-вывода. –

+0

Вместо этого он должен быть stdout, stdin - для ввода, переданного дочернему процессу – helado

4

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

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

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

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

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

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

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

2

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

+1

Это кажется неподдерживаемым, вы можете использовать https://github.com/icodeforlove/task.js (что изоморфно) –

3

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

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 
}); 
Смежные вопросы