Ускорите код?
Уважаемые знатоки, возможно ли ускорить функцию groupBy хотя бы в 1,5 раза (для node.js)? :)
/** * Group items by field * * items = [ * {id: 1, name: 'A', val: 1, smth: true}, * {id: 2, name: 'B', val: 2, ...}, * {id: 3, name: 'A', val: 3, ...}, * {id: 4, name: 'B', val: 4, ...}, * {id: 5, name: 'A', val: 5, ...} * ] * * groupBy(items, 'name', ['val', ...]) = * [ * { * groupField: 'name', * groupValue: 'A', * * // Items of the group * items: [{id: 1, name: 'A', val: 1, , smth: true}, {id: 3, name: 'A', val: 3}, {id: 5, name: 'A', val: 5}], * * // Values of first item * id: 1, * smth: true, * ... * * // Summed values * val: 9, * ... * }, { * groupField: 'name', * groupValue: 'B', * items: [{id: 2, name: 'B', val: 2}, {id: 4, name: 'B', val: 4}], * id: 2, * val: 6, * ... * } * ] * * @param items - Array<any> - items array * @param field - string - field name * @param sumFields - Array<string> - array with names of fields which should be summed * @returns Array<any> */ function groupBy(items, field, sumFields = []) { const groupsMap = {}; for (let i = 0; i < items.length; i++) { const item = items[i]; const groupValue = item[field]; let group = groupsMap[groupValue]; if (!group) { group = {items: [], groupField: field, groupValue: groupValue, ...item}; groupsMap[groupValue] = group; } // Add values which should be summed for (let j = 0; j < sumFields.length; j++) { const fieldName = sumFields[j]; const sumValue = item[fieldName]; if (sumValue) { group[fieldName] += sumValue; } } group.items.push(item); } return Object.keys(groupsMap).map(key => groupsMap[key]); } function generateData(amount) { return Array.from({length: amount}, (v, i) => { return { id: i, group: String.fromCharCode(Math.floor(Math.random() * 25) + 65), string: Math.random().toString(36).substring(2), number: Math.random() * 100, number2: Math.random() * 1000, null: null, undefined: undefined, boolean: true } }) } const data = generateData(100000) console.time('Groupping') grouped = groupBy(data, 'group', ['number', 'number2']) console.timeEnd('Groupping') |
Shitbox2, что у вас делает 70-я строчка?
Upd. еще для ускорения можно попробовать перебирать массив сразу с двух сторон. |
Цитата:
Самая тяжелая операция тут - let group = groupsMap[groupValue] Цитата:
|
Цитата:
Цитата:
Цитата:
И в своем коде вы замеряете не только скорость работы вашей функции группировки, но и скорость генерации ваших данных. |
>> возможно ли ускорить функцию groupBy
Врятли. По сути тут идет простая итерация всего объекта с простым условным ветвлением для фильтрации значений по установленным признакам. Можно развернуть цикл делая по двадцать итераций за проход но с такими оптимизациями интерпретатор и сам справляется. Тут с логикой проблема, управление данными осуществляется в приложении алгоритмами собранными топориком на коленке. Задачи связанные с группировкой, хранением, сортировкой, индексацией и выборкой данных лучше решать с помощью баз данных. |
Цитата:
Более того этот объект изменяется на текущей итерации цикла т.е. пока не закончится текущая итерация и объект не будет изменен следующую/параллельную итерацию интерпретатор выполнять не может так как состояние объекта еще не определенно что работает как брошенный якорь на гоночном автомобиле. Основной способ оптимизации выполнения это избавление от побочных эффектов при выполнении блока кода или вынос их в отдельный блок кода. А строки 50, 67 как раз и есть эти побочные эффекты. Но данные во внешнем изменяемом объекте не пересекаются по этому если в ручную развернуть цикл то это должно дать прибавку к скорости. Хотя оптимизатор наверно и сам может просчитать что данные не пересекаются и ожидать изменения объекта не обязательно. |
|
Попробовать использовать Map вместо объекта.
Группы сразу пушить в массив, который вернуть вместо выражения на строке 70. Читерство: суммируемые поля оформить как проперти, можно с мемоизацией. |
Цитата:
Он ничего не разворачивает. |
Цитата:
Прямая ссылка на исходник где происходит оптимизация турбофаном в V8 https://github.com/v8/v8/blob/4b9b23...eline.cc#L1064 Если вкратце то турбофан пытается байткод виртуальной машины V8 транспилировать в машинный код текущего процессора. Причем с такой PGO оптимизацией что компиляторы C/C++ пускают слюни от зависти. Ничего необычного пытается заинлайнить методы и развернуть цыклы где это удается ну и еще дефрагментирует расположение данных в памяти. |
Часовой пояс GMT +3, время: 14:37. |