Comments 29
Планируются ли оптимизации что бы можно было создавать генерируемые конструкторы, которые не сильно бы уступали в скорости инициализации обычным?
Так что бы инициализация 1000 штук generatedClass1 или generatedClass2 не уступала OldClass
Так что бы инициализация 1000 штук generatedClass1 или generatedClass2 не уступала OldClass
var OldClass = function() {
this.track = null;
this.artist = null;
this.full_title = null;
this.url = null;
}
new OldClass();
var getSetter = function(prop, callback) {
return function(obj){
obj[prop] = null;
callback(obj);
};
};
var realDyn = function(array) {
// на основе списка свойств функция генерирует
// функцию, которая не использует итерация
var curSetter = function(){};
for (var i = array.length - 1; i >= 0; i--) {
curSetter = getSetter(array[i], curSetter);
}
return curSetter;
};
var gen = realDyn(['track', 'artist', 'full_title', 'url']);
var GeneratedClass1 = function(){
gen(this);
};
new GeneratedClass1();
var make = function(array) {
return function () {
for (var i = 0; i < array.length; i++) {
this[array[i]] = null;
}
};
};
var GeneratedClass2 = make(['track', 'artist', 'full_title', 'url']);
new GeneratedClass2();
+2
Зачем такие конструкции?
+3
Для того чтобы автоматически создавать эффективные констукторы на базе которых будет создана тысяча другая объектов, набор полей которых ограничен (задаётся разработчиком не напрямую, но может быть определён с помощью алгоритма), но для которых крайне неудобно или невозможно написать тело на момент написания кода.
Либо eval. Что не всегда возможно и просто небезопасно
(как вы знаете браузерные движки очень хорошо оптимизируют такой код)
Либо извращения с предварительной компиляцией.
Либо оптимизации движком.
Либо eval. Что не всегда возможно и просто небезопасно
var evaledConstr = function(props) {
var body = '"use strict";\n';
for (var i = 0; i < props.length; i++) {
body += 'this["' + props[i] + '"] = null;\n';
}
return new Function(body);
};
var EvaledConstr = evaledConstr(['track', 'artist', 'full_title', 'url']);
new EvaledConstr();
(как вы знаете браузерные движки очень хорошо оптимизируют такой код)
var Contr = function(){
this.myName = null;
};
Либо извращения с предварительной компиляцией.
Либо оптимизации движком.
+1
del
0
Все оптимизации уже есть.
Код ниже должен исполнятся на реальных данных так же быстро как и «нативный».
В JS нету «классов». Это неуместный сахар для людей из других языков.
Проще сразу думать via prototype-chain и не возвращаться к «классам».
Код ниже должен исполнятся на реальных данных так же быстро как и «нативный».
var artistProps = {
track: { writable: true },
artist: { writable: true },
full_title: { writable: true },
url: { writable: true}
};
var ArtistProto = Object.create(Object.prototype, artistProps);
var artists = [];
for (var i = 0; i < 1000; i++) {
artists.push(Object.create(ArtistProto));
}
В JS нету «классов». Это неуместный сахар для людей из других языков.
Проще сразу думать via prototype-chain и не возвращаться к «классам».
0
Спасибо за совет, не знал про второй аргумент Object.create. Думаю, это то что нужно для моей задачи, осталось проверить производительность. (а наследование для этой задачи не нужно)
0
Не думаю что есть смысл думать о производительности:
The Black Cat of Microbenchmarks
Прочитайте весь блог разработчика
The Black Cat of Microbenchmarks
Прочитайте весь блог разработчика
-1
Оказалось, что Object.create для этой задачи бесполезен
measure 441
measure 5436
var mes = function(callback) {
var start = new Date();
callback();
console.log('measure', new Date() - start);
};
var OldClass = function() {
this.track = null;
this.artist = null;
this.full_title = null;
this.url = null;
};
var artistProps = {
track: { writable: true },
artist: { writable: true },
full_title: { writable: true },
url: { writable: true}
};
mes(function() {
var items = [];
for (var i = 0; i < 1000000;i++) {
items.push(new OldClass());
}
});
mes(function() {
var items = [];
for (var i = 0; i < 1000000;i++) {
items.push(Object.create(null, artistProps));
}
});
measure 441
measure 5436
+1
Ну напишете так:
какая разница.
// measure 372
// measure 365
Alt code
_ = require('lodash');
var mes = function(callback) {
var start = new Date();
callback();
console.log('measure', new Date() - start);
};
var OldClass = function() {
this.track = null;
this.artist = null;
this.full_title = null;
this.url = null;
};
mes(function() {
var items = []
for (var i = 0; i < 1000000;i++) {
items.push(new OldClass());
}
});
var artistProps = {
track: null,
artist: null,
full_title: null,
url: null
}
var MainArtist = function() {};
_.forEach(artistProps, function(value, key){
MainArtist[key] = value;
})
mes(function() {
var items = [];
for (var i = 0; i < 1000000;i++) {
items.push(new MainArtist());
}
});
var r = {};
какая разница.
// measure 372
// measure 365
-1
var MainArtist = function() {};
_.forEach(artistProps, function(value, key){
MainArtist[key] = value;
})
а какой смысл в этом коде, если MainArtist[key] и (new MainArtist())[key] не имеют никакой связи?
+1
MainArtist.prototype[key] = value; и связь через прототипы.
-1
всё таки
это не
а наследование для задачи не нужно — нужны быстрые конструкторы
var MainArtist = function() {};
_.forEach(artistProps, function(value, key){
MainArtist[key] = value;
})
это не
var MainArtist = function() {};
_.forEach(artistProps, function(value, key){
MainArtist.prototype[key] = value;
})
а наследование для задачи не нужно — нужны быстрые конструкторы
+1
Prototype Chain всегда будет самым быстрым в JS. Особенно на реальных данных, а не на тестах кторые непонятно что показывают.
Запустите себе
и загрузите данные из вашего скрипта в IR Hydra.
И там можно посмотреть как v8 ваш measure обманывает.
Запустите себе
node --trace-hydrogen --trace-deopt --code-comments --print-opt-code constr.js > code.asm
и загрузите данные из вашего скрипта в IR Hydra.
И там можно посмотреть как v8 ваш measure обманывает.
0
«Prototype Chain всегда будет самым быстрым в JS»
конечно же нет! youtu.be/tCG0aPNvkTs?t=10m39s
всегда быстрей взять свойство непосредственно с объекта, чем с его прототипа
особенно бессмысленно его использовать когда нужно создать сразу правильный hidden class для объектов у которых общий набор полей но значения полей у всех разные
www.youtube.com/watch?v=tCG0aPNvkTs
опять таки: задача сделать констуктор сравнительно эффективный такой же как
при условии, что на этапе написания кода нет набора полей (this.x = x;), но он будет и будет ограничен после выполнения некоторого кода
конечно же нет! youtu.be/tCG0aPNvkTs?t=10m39s
всегда быстрей взять свойство непосредственно с объекта, чем с его прототипа
особенно бессмысленно его использовать когда нужно создать сразу правильный hidden class для объектов у которых общий набор полей но значения полей у всех разные
www.youtube.com/watch?v=tCG0aPNvkTs
опять таки: задача сделать констуктор сравнительно эффективный такой же как
function Point(x, y) {
this.x = x;
this.y = y;
}
при условии, что на этапе написания кода нет набора полей (this.x = x;), но он будет и будет ограничен после выполнения некоторого кода
+2
«конечно же нет!» Конечно же да. Вы же конкретно пишете «нужны быстрые конструкторы».
Задача «задача сделать констуктор сравнительно эффективный» решается, в том числе и через прототипы.
Ваш бенчмарк меряет только скорость конструктора со свойствами. Не понимаю зачем вы меняете тему.
Задача «задача сделать констуктор сравнительно эффективный» решается, в том числе и через прототипы.
Ваш бенчмарк меряет только скорость конструктора со свойствами. Не понимаю зачем вы меняете тему.
-1
не быстрые, а эффективные.
задача чтобы и конструктор быстро исполнялся и сразу создавался правильный hidden class для объекта. задачи наследования, задачи получения доступа к неким общим свойствам не стоит
задача чтобы и конструктор быстро исполнялся и сразу создавался правильный hidden class для объекта. задачи наследования, задачи получения доступа к неким общим свойствам не стоит
0
Инженеры Chrome отвечают, что подобная конструкция (с созданием генерируемых конструкторов) довольно сложна для оптимизации производительности до уровня конструкции с OldClass. Для решения подобной задачи стоит подумать об использовании eval-а для создания функции конструктора, которая напрямую установит желаемые свойства.
+1
А раз он переписан с нуля, может V8 в V9 переименовать пора? ;)
+1
А что насчет остальных тестов из октана, а не только zlib? А других бенчмарков, вроде SunSpider?
0
В данный момент Turbofan сильно тормознутее предыдущего их движка, поэтому, видимо, для статьи был выбран отдельный бенчмарк, где виден прирост производительности. Хотя AWFY с этим не согласен.
+2
Я думаю, в первую очередь, TurboFan сейчас ещё просто на сравнительно ранней стадии разработки. Что успели хорошо отладить и вылизать — то поставили в продакшен на исполнение реального кода и сбор статистики. А остальное — наверстают со временем, не просто же так они с нуля переделывают JIT-компилятор.
+2
Как написано в статье, TurboFan сейчас заточен на ограниченный перечень фич, который CrankShaft не может оптимизировать нормально. И постепенно Turbofan будет пополнять список этих фич, и заменит CrankShaft. Те тесты запускаются чито на TurboFan, без CrankShaft
0
UFO just landed and posted this here
V8 не работает как чистый интерпретатор, навроде Бейсика, вместо этого он компилирует функции в момент когда они вызываются в первый раз. Компиляция происходит очень быстро, используется очень простой компилятор, оптимизированный на время компиляции, а не на время исполнения.
Для каждой функции запоминается количество вызовов, и когда оно превышает некий порог, вызывается «более крутой» компилятор, оптимизирующий, который имеет имя собственное CrankShaft, что в переводе значит, кажется, «коленчатый вал» (передающий вал двигателя).
CrankShaft компилирует долго, старательно оптимизирует. Его написали далеко не сразу, в первых версиях v8 его не было. Он вообще долгое время считался экспериментальной фичей.
Прошли годы, и в базе идей для CrankShaft накопилась куча предложений по улучшению, и вот, наконец, решили сделать следующий логический шаг: переписать «с нуля». Хотя, я подозреваю, что много кода, всё-таки перетащат.
Кто именно сейчас возглавляет работу не знаю, изначальный дизайн, вроде, был Ларса Бака, известного гуру по виртуальным машинам и оптимизации компиляторов.
Для каждой функции запоминается количество вызовов, и когда оно превышает некий порог, вызывается «более крутой» компилятор, оптимизирующий, который имеет имя собственное CrankShaft, что в переводе значит, кажется, «коленчатый вал» (передающий вал двигателя).
CrankShaft компилирует долго, старательно оптимизирует. Его написали далеко не сразу, в первых версиях v8 его не было. Он вообще долгое время считался экспериментальной фичей.
Прошли годы, и в базе идей для CrankShaft накопилась куча предложений по улучшению, и вот, наконец, решили сделать следующий логический шаг: переписать «с нуля». Хотя, я подозреваю, что много кода, всё-таки перетащат.
Кто именно сейчас возглавляет работу не знаю, изначальный дизайн, вроде, был Ларса Бака, известного гуру по виртуальным машинам и оптимизации компиляторов.
+4
Sign up to leave a comment.
Прокачиваем JavaScript с помощью TurboFan