асинхронный и ожидающий в массиве многих объектов, т.е. более 1000

#javascript #node.js #cassandra

#javascript #node.js #cassandra

Вопрос:

У меня есть более 1000 массивов объектов с такими свойствами, как:

const empArr = [{ EmpName: ‘sds’, EmpID: ‘e3′, dob: ’22-12-2’, .. и так далее }];

Я попробовал постановку задачи, используя promise.all (обещания), но я хочу сделать это более эффективно.Итак, мне нужна некоторая помощь

 function makeDBInsert(empArr) {
const dbArr = [];
const promises = [];
const LEN = empArr.length;

/** this function returns promise containing emp age **/
function getEmpAge(empId) {
return db.execute('select age from emp where "empId" = ?', [empId]);
} 

for (let i = 0; i < LEN; i  = 1) {
const obj = {
name: empArr[i].empName, 
empId: empArr[i].empId
}
promises.push(getEmpAge(obj.empId);
dbArr.push(obj);
}

return Promise.all(promises).then((empDetail) => {
const dbObj = empDetail.map((emp, i) => {
return {
dbArr[i].age: emp.age
}
});
return db.insert('insert into emp ("name", "id", "age") values ('?', '?', '?');', Object.values(obj));
}).catch(err => console.error(err));
} 
  

Итак, здесь empArr имеет более 1000 объектов в массиве. Здесь я извлекаю возраст emp из базы данных, которая возвращает мне обещание, содержащее идентификатор emp. Я использую promise.all для выполнения этой работы, вместо этого есть ли лучший способ обойтись без использования promise.все, а затем повторение? Заранее спасибо.

Примечание: Пожалуйста, игнорируйте синтаксические ошибки в коде. Моя цель здесь — просто описать мою постановку задачи.

Комментарии:

1. Я не очень хорошо знаю Cassandra, но не могли бы вы просто запросить DB, например select age from emp where empId IN (1,2,3,4.....1000) ? Таким образом, вы выполняете только один запрос вместо 1000 из них

2. «… о предотвращении promise.all» — но почему?

3. Себастьян прав, узким местом здесь являются эти тысячи запросов, вот что вам следует оптимизировать.

4. @SebastianKaczmarek «Может быть, вы могли бы также выполнить только один запрос для изменения ваших данных?» В Cassandra использование IN ключа раздела переносит основную нагрузку на узел-координатор. Это нормально для 4 или 5 элементов (хотя это не будет хорошо работать), но, конечно, не 1000. Если таблица не предназначена для поддержки возврата 1000 строк в одном запросе, то лучшим вариантом является выполнение 1000 отдельных запросов.

5. @Aaron спасибо, не знал этого. Как я уже говорил ранее, я не очень хорошо знаю Cassandra. Тем не менее, решение OP с async / await — ужасная идея, и он должен избегать этого

Ответ №1:

Я получил решение, т. е. один цикл делает все, как с использованием IIFE, async await, без обещания.все и повторение ответа promises.

 async function makeDBInsert(empArr) {
const modifiedArr = [];

function getEmpAge(empId) {
return db.execute('select age from emp where "empId" = ?', [empId]);
} 


await (function doDBCalls() {
empArr.forEach(async (item, i) => {
 /* getEmpAge(param) is DB call */
    const res = await getEmpAge(item.empId);
    modifiedArr.push({modified: res.age });
    // modify the object here and batch insert 
});
})();
} 
  

Комментарии:

1. Ой! Вы сделали здесь ужасную вещь. Вы выполняете итерацию 1000 раз, и на каждой итерации вы создаете обещание и ждете его выполнения , а затем начинаете другую итерацию. Это намного хуже, чем Promise.all решение, поскольку вы вообще не избавились от обещаний (как я предлагал в комментариях) и (что здесь самое большое узкое место) вы катастрофически замедляете выполнение вашего кода. Таким образом, вы не используете асинхронное выполнение кода — вы заставляете код здесь выполняться как синхронный, что значительно замедляет работу вашего приложения!

2. Да, я заставляю его работать синхронно, потому что я не хочу повторять цикл несколько раз, что делает процессор интенсивным. И входящие в БД вызовы [await getEmpAge(param) ] Nodejs (что очень хорошо для операций ввода-вывода) и Cassandra работают очень хорошо. Cassandra в кластере с одним узлом может обрабатывать не менее 50 тыс. транзакций в секунду. Это синхронно, но не замедляется.

3. Моя точка зрения здесь в том, что await в forEach приводит к зависанию кода до тех пор, пока не будет выполнено обещание от getEmpAge , затем он размораживается и продолжает итерацию. Таким образом, на каждой итерации вы заставляете свой код ждать завершения запроса, а затем продолжать с остальной частью кода на текущей итерации, а затем запускать другую. Если бы вы использовали Promise.all , вы бы создали 1000обещаний (которые вы создаете в любом случае здесь), которые выполняются асинхронно, и время, которое вам пришлось бы их ждать, было бы равно только времени, необходимому для самого длительного выполнения. Теперь это равно их сумме

4. Пожалуйста, посмотрите пример теста, который я только что создал: jsben.ch/uyfPG . Это показывает, как async/await замедляется код в таком случае. Хотя есть две итерации empArr , код по-прежнему выполняется намного быстрее, потому что методы массива в JavaScript работают очень быстро.