что является лучшим способом обработки длительных синхронных / блокирующих задач в узле - PullRequest
0 голосов
/ 11 мая 2018

Итак, допустим, мы хотим найти сумму всех чисел в очень очень длинном массиве. Есть два способа сделать это без блокировки цикла событий.

  1. использование узла с использованием дочернего процесса

  2. создание асинхронной функции для добавления и использования ее для нахождения суммы всех чисел.

    import awaitEach from 'await-each';
    
    
    function makeItAsync(myFunc){
     return function(...args){
    
       return new Promise(function(resolve,reject){
         setImmediate(function(){
           var result = myFunc(...args);
           resolve(result);
         });
      });
    
     }
    }
    
    function add(a,b){ return a + b}
    
    var asyncAdd = makeItAsync(add);
    
    var list = [1,2,3,4,5,6,7,8,9.........];
    var sum = 0;
    
    await awaitEach(list, async function(n){
        sum = await asyncAdd(n,sum);
    })
    
    console.log(sum);
    

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

Хотелось бы узнать, что лучше с точки зрения производительности (процессор, память).

  • Является ли один из них более подходящим подходом при большом количестве запросов.
  • Какой из них быстрее.
  • Какой из них занимает больше памяти.

1 Ответ

0 голосов
/ 11 мая 2018

setImmediate() и setTimeout() могут казаться чем-то асинхронным, потому что они не блокируют сразу, но на самом деле они не решают проблему длительных задач блокировки. Они планируют выполнение задач позже, но когда они будут запущены, это будет продолжительная задача, которая блокирует цикл обработки событий до его завершения. Итак, ваша makeItAsync() функция действительно не более полезна, чем просто запуск оригинальной функции с setTimeout().

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

  1. Разбейте длительные задачи на очень маленькие части работы, каждая из которых может быть выполнена за несколько миллисекунд. После того, как вы закончите одну часть работы, запланируйте следующую часть работы с коротким setTimeout(), и это позволит циклу обработки событий обрабатывать другие события между вашими работами. Обычно для этого требуется переписать долгосрочную задачу (почти в конечный автомат), а иногда ее сложно спроектировать и поддерживать для некоторых типов обработки.

  2. Запустите дочерний процесс и отправьте долгосрочную задачу дочернему процессу. Тогда ваш главный цикл обработки событий полностью свободен от длительных задач. Дочерний процесс может просто сообщить результат, когда это будет сделано. Если вам приходится многократно выполнять эту задачу, вы можете создать рабочую очередь и набор дочерних процессов, которые будут работать с задачами в очереди, отправляя сообщение родителю, когда они будут выполнены. Это обычно довольно легко сделать. Как только недостатком является то, что дочерний процесс не имеет прямого доступа к данным в основном процессе, поэтому, если долго выполняющимся задачам требуется доступ к большому количеству данных из основного процесса, то вам необходимо разработать способ совместного использования данных (возможно, помещать данные в другой процесс, например, в redis, где к нему могут обращаться несколько процессов).

...