#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 работают очень быстро.