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

server.listen(3001, () => {
doFullScan();
});

async function doFullScan() {
    while (true) {
        await collectAllData();
    }
}

collectAllData() - это метод, который проверяет доступные проекты, просматривает каждый проект, собирает некоторые данные и записывает их в базу данных.

async function collectAllData() {
    //doing soemhting
    const projectNames = ['array with projects name'];

    //this loop takes too much of time
    for(let project in projectNames){
        await collectProjectData(project);
   }
   //doing something
}

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

Как мне это сделать?

Существует кластерная библиотека с примерами на https://nodejs.org/docs/latest/api /cluster.html, но я не хочу создавать новые серверы. Я хочу создать детей, которые выполнят задание и выйдут после того, как сделают свою работу.

Итак, есть const { fork } = require('child_process');, но я не совсем уверен, как заставить каждую вилку запускать только метод collectProjectData().

0
Łukasz Szczesiak 13 Мар 2018 в 16:09

2 ответа

Лучший ответ

Вы можете сделать это изначально без каких-либо сторонних библиотек. Прямо сейчас ваши for...loop работают один за другим.

Опция 1

Используйте Promise.all и .map

await Promise.all(projectNames.map(async(projectName) => {
  await collectProjectData(projectName);
});

Обратите внимание: если вы используете .map, он запустит их все одновременно, что может быть слишком много, если projectNames продолжит расти. Это полная противоположность тому, что вы делаете сейчас.

Вариант 2

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

const chunk = (a, l) => a.length === 0 ? [] : [a.slice(0, l)].concat(chunk(a.slice(l), l));
const batchSize = 10;
const projectNames = ['array with projects name'];

let projectNamesInChunks = chunk(projectNames, batchSize);
for(let chunk of projectNamesInChunks){
  await Promise.all(chunk.map(async(projectName) => {
    await collectProjectData(projectName);
  });
}
1
wjvander 13 Мар 2018 в 13:42

Я рекомендую использовать Promise.map http://bluebirdjs.com/docs/api/promise.map.html

Таким образом вы можете контролировать уровень параллелизма, как хотите:

await Promise.map(projectNames, collectProjectData, {concurrency: 3})
0
OhadBasan 13 Мар 2018 в 13:23