Почему фабрики/закрытия JS намного медленнее, чем конструкторы/прототипы?

Когда-то фабрики/закрытия в JS были в пределах 15 процентов от конструкторов/прототипов. Сегодня разница составляет более 8000% в пользу прототипов (а прототипы используют примерно половину памяти).

https://jsperf.com/prototype-vs-factory-performance/4

Замыкания (теоретически) не создают больше объектов. У вас есть замыкание и экземпляр вместо прототипа и экземпляра (и у замыканий есть еще одно преимущество, потому что вы не можете добавлять/удалять из них свойства). Мой единственный вывод заключается в том, что, хотя функции являются примитивными и неизменяемыми (хотя функциональные объекты - нет), они не интернированы, вызывая скачки кэша инструкций. Эта разница проявляется в движках JS.

Есть ли у кого-нибудь реальные факты о том, почему существует такое огромное несоответствие?


person Elijah Dorman    schedule 28.12.2018    source источник


Ответы (1)


Замыкания (теоретически) не создают больше объектов.

Этот стиль создания объекта «замыкание/фабрика» действительно создает больше объектов: при использовании прототипов экземпляры методов прототипа являются общими, тогда как в стиле «фабрики» каждый экземпляр объекта получает свою собственную копию всех методов. Это можно наблюдать, так что это не то, что движок может просто оптимизировать. Рассмотреть возможность:

var x1 = createValueObject();
var x2 = createValueObject();
x1.get.my_tag = 42;
console.log(x2.get.my_tag);      // undefined
console.log(x2.get === x1.get);  // false

var y1 = new ValueObject();
var y2 = new ValueObject();
y1.get.my_tag = 123;
console.log(y2.get.my_tag);      // 123
console.log(y2.get === y1.get);  // true

Я хотел бы подчеркнуть, что в целом использование замыканий и фабрик совершенно нормально; этот пункт здесь относится только к этому конкретному шаблону создания объектов.


https://jsperf.com/prototype-vs-factory-performance/4

Это также отличный пример: Остерегайтесь вводящих в заблуждение микробенчмарков!

Всякий раз, когда вы видите сотни миллионов операций в секунду в тесте jsperf.com, почти наверняка оптимизирующему компилятору удалось удалить весь ваш код, и вы измеряете пустые циклы. Никакая реальная операция не может быть такой быстрой.

В данном случае это неудивительно: использование прототипов — это идиоматический способ определения/создания объектов в JavaScript, и движки прилагают много усилий для оптимизации каждого аспекта этого шаблона, поэтому современные движки имеют возможность чтобы отслеживать, какие методы прототипа вызываются, встраивать их в конечном итоге (не сразу, только в горячем коде!), выяснять, что они не дают полезных результатов, и отбрасывать весь бесполезный код.

Я ожидаю, что при надлежащем тщательном тестировании то, что вы называете шаблоном «конструкторы/прототипы», по-прежнему значительно быстрее, но не так быстро, как ошибочно указывают текущие результаты.


перебор кэша инструкций

Нет, кэш инструкций здесь ни при чем.

Когда-то фабрики/закрытия в JS были в пределах 15 процентов от конструкторов/прототипов.

Мне трудно поверить, что такое было когда-либо за последние десять лет. Может быть, 20 лет назад, когда все было как собака медленно?

person jmrk    schedule 28.12.2018
comment
Зачем нужны копии функций? Разве указатель на интернированную функцию не позволит совместно использовать одну и ту же функцию между объектами? Поскольку форма результирующих литералов идентична и встречается в одной и той же точке кода, не должно ли быть возможно совместное использование скрытого класса? Если вы итерируете десятки одинаковых функций с разными участками памяти, постоянно переключаясь между кешем, разве это не перебор кеша по сравнению с повторным запуском одних и тех же 5-6 функций? - person Elijah Dorman; 28.12.2018
comment
Как показывает фрагмент кода, наличие копий объектов функций можно наблюдать (программы могут полагаться на это); другими словами, спецификация JavaScript требует наличия копий. Их код будет общим для большинства движков (следовательно, не будет эффектов кэширования инструкций), но объекты должны быть отдельными. Скрытые классы не меняют этого. - person jmrk; 30.12.2018