Почему создание новых объектов с буквенно-цифровыми ключами настолько медленное в новых версиях node?
Я запускаю этот тест в разных версиях node:
function test() {
var i;
var bigArray = {};
var start = new Date().getTime();
for (i=0; i<100000; i+=1) {
bigArray[i] = {};
var j= Math.floor(Math.random() * 10000000);
bigArray[i]["a" + j] = i.toString(32);
if (i % 1000 === 0) console.log(i);
}
var end = new Date().getTime();
var time = end - start;
console.log('Execution time: ' + time);
}
test();
Как вы можете видеть, он просто создает объект с 100000 полями, где каждое поле является всего лишь объектом с одним полем. Ключ этого внутреннего объекта вынужден быть буквенно-цифровым (если клавиша является числовой, она работает нормально).
Когда я запускаю этот тест в разных реализациях/версиях javascript, я получаю следующие результаты:
v0.8.28 -> 2716 ms
v0.10.40 -> 73570 ms
v0.12.7 -> 92427 ms
iojs v2.4.0 -> 510 ms
chrome -> 1473 ms
Я также попытался запустить этот тест в асинхронном цикле (каждый шаг цикла в другом тике), но результаты аналогичны результатам, показанным выше.
Я не могу понять, почему этот тест настолько дорогой в новых версиях node.
Почему это так медленно?
Есть ли специальный флаг v8, который может улучшить этот тест?
Ответы
Ответ 1
Для обработки больших и разреженных массивов существует два типа хранилищ массивов:
- Быстрые элементы: линейное хранилище для компактных наборов клавиш
- Элементы словаря: хэш-таблица хранения в противном случае
Лучше не переводить хранилище массивов из одного типа в другой.
Таким образом:
- Используйте непрерывные клавиши, начинающиеся с 0 для массивов
- Не предопределяйте большие массивы (например, > 64K элементов) до их максимального размера, а вместо этого увеличивайтесь по мере продвижения
- Не удалять элементы массивов, особенно числовые массивы
- Не загружать неинициализированные или удаленные элементы
Источник и дополнительная информация: http://www.html5rocks.com/en/tutorials/speed/v8/
PS: это должно значительно улучшиться в предстоящей версии node.js + io.js.