Как стать автором
Обновить

Комментарии 29

НЛО прилетело и опубликовало эту надпись здесь
Когда-то это называлось «дырявой абстракцией», а предлагаемые лайфхаки — «преждевременной оптимизацией». Также вы забыли упомянуть, что сам Number является по спецификации числом с плавающей точкой двойной точности, и для double-ов деление на 15000 ничем принципиально не отличается от деления на степень двойки, так же как и не определены битовые операции.

Но так как VM использует внутренние оптимизации представления вида «считать беззнаковым 32-битным целым, пока не будет доказано обратное», это сработает. Так что тут «кротовьи норы» второго порядка.

Стоит ли их использовать? Я бы сказал, что нет. Код должен быть читабельным и понятным другому инженеру, который ничего не знает о вашем продукте. И только если результат читабельного кода медленный, и только если профилировщик покажет, что узкое место — конкретно в операции остатка от деления, то только тогда следует придумывать оптимизации.
НЛО прилетело и опубликовало эту надпись здесь
Код должен быть читабельным и понятным другому инженеру, который ничего не знает о вашем продукте.

Но знает язык на должном уровне, согласны? И, очевидно, примерно помнит, чему равны степени двойки.
Я к тому, что приведённые примеры — не ухудшают читаемости кода. Для программиста число 65536 должно быть не более «магическим», чем 1000. А что память быстрее всего копировать блоками, равными разрядности шины — это общеизвестный факт.
Никакого занудства, всё правильно. 2^16=65536, поэтому два байта кодируют с 0 по 65535.

Про преждевременные оптимизации и читабельность твердят на каждом шагу. Как будто это что-то плохое. В результате имеем тонны тормозных решений просто потому, что инженеры с умным видом сцат писать иначе.

и для double-ов деление на 15000 ничем принципиально не отличается от деления на степень двойки

Нет разницы только в процессорах последних поколений:
https://www.agner.org/optimize/instruction_tables.pdf

НЛО прилетело и опубликовало эту надпись здесь
Спасибо, крутой чел) разберусь как он реализовал torrent на node.js
это интересные знания, если хочется получше разобраться, как работает движок. но «не пытайтесь повторить это дома». даже если это и даёт прирост в скорости (что само по себе не известно, нужно ли вашему приложению) — поддерживаемости коду это точно навредит
Зачем вводить новый термин «кротовая нора», когда на самом деле это просто оптимизация? Чтобы звучало модно, стильно, молодежно?
Видимо, какой-то англоязычный жаргонизм, калькированный переводчиком.

Wormholes же в оригинале. И картинка намекает, а перевод не очень удачный. Wormholes в данном случае типа залез в чёрную дыру тут, а вылез в 100 млн парсеков (за 1000 лет до рождения). Червоточины, возможно, было бы точнее и понятнее

Это не претензия к переводчику, а вопрос по существу. Что из описанного в статье нельзя было считать обычной оптимизацией?

Все являются, конечно. Главная идея статьи (поста в блоге в оригинале) в последней фразе. Перефразируя "JS такой высокоуровневый, а битовые хаки для оптимизации все равно работают".

Почти всё. Тот факт, что операции с «нетипизированными данными», которые на самом деле «Number», которые типа как «double», но на самом деле «uint32» и оптимизатор про это знает — очень серьёзно опирается на реализацию многих вещей.

То есть фактически подобные вещи «пробивают» все мнгочисленные слои абстракций, которые пытаются сделать вид, что JS — это такая себе сущность, описанная в спецификации… и никакого отношения к ассемблеру не имеет… а оказывается, что нет — таки имеет…

И что характерно, на самом деле многие скриптовые/высокоуровневые языки такими "битовыми" хаками особо не пооптимизируешь. Вот из того, что помню


  • SQL — за современный Postgres с Jit не скажу, но в MS SQL Server/MySQL/Oracle/PostgreSQL разница на уровне погрешности.
  • VB/VBS/VBA. Некоторые приемы работают, но только при строгой типизации. Variant или работа с COM мгновенно съедают разницу.
  • 1С — там арифметика на своём "особенном" числовом типе. Этот тип раз в 100 медленнее Int32. Сдвигов и битовой логики нет.
  • Powershell — с ним смешно. Я лет 6 назад с удивлением обнаружил, что типизированные переменные медленнее нетипизированных. Там просто при каждом присваивании для типизированных переменных происходит принудительное приведение к типу.
  • Bash, cmd — не найти разницу

Да и JS стал таким чувствительным к битовым хакам примерно с появлением "дерзкого" V8, потом остальные стараются догнать (кто не верит — ставьте виртуалку с IE6 и проверьте).

Если вы привыкли видеть сквозь синтаксис Javascript макроассемблер, то конечно ни чего необычного. Просто обычно вопросы оптимизации замыкаются на языка и библиотек (for-of vs .forEach(), DOM vs jQuery и т.п.). smile)

Умные компиляторы или VМ способны производить такую оптимизацию превращая за кулисами операцию получения остатка в побитовую операцию и обратно. По факту последняя V8 Javascript VM (не реализовано в NodeJS) делает именно так.

NodeJS 11 вышла и там апдейт V8 до последней версии, может уже и реализовано.

Пока не заглянул в MDN, не смог понять, что Math.clz32 возвращает количество лидирующих нулевых битов в 32-битном двоичном представлении числа.

Огромное спасибо! Поправил

Функция copy (та, которая использует Float64Array) иногда копирует данные неправильно. Даже если длина массива делится на 8. Это хороший пример того, как "умная" оптимизация может приводить к появлению трудно обнаруживаемых ошибок.

НЛО прилетело и опубликовало эту надпись здесь

Под спойлером — пример массива, который копируется неправильно. Но я предлагаю перед тем, как заглядывать туда, попробовать найти проблему самостоятельно.


Код
let input = new Uint8Array(8).fill(255);
let output = new Uint8Array(8);
copy(input, output);
console.log(input, output);

Объяснение

При декодировании данных как Float64, получается значение NaN. Это единственное значение, у которого есть несколько различный представлений (хотя значения +0 и -0 выглядят как равные для операторов == и ===, они являются различными). Согласно стандарту, в JavaScript все значения NaN неразличимы:


The Number type has exactly 18437736874454810627 (that is, 264−253+3) values, representing the double-precision 64-bit format IEEE 754-2008 values as specified in the IEEE Standard for Binary Floating-Point Arithmetic, except that the 9007199254740990 (that is, 253−2) distinct “Not-a-Number” values of the IEEE Standard are represented in ECMAScript as a single special NaN value. (Note that the NaN value is produced by the program expression NaN.) In some implementations, external code might be able to detect a difference between various Not-a-Number values, but such behaviour is implementation-dependent; to ECMAScript code, all NaN values are indistinguishable from each other.

При кодировании в байты, скорее всего, будет использоваться не то представление NaN, которое было в исходном массиве (стандарт не указывает, какое именно нужно использовать, так что результат зависит от реализации), поэтому скопированные данные не будут совпадать с исходными.

Спасибо!
Нутром чуял, что нельзя байтовый массив безболезненно в массив Float-ов сконвертить… Не знал почему, но со времён школы и QBasic-а натыкался на порчу данных при этом процессе.
В js появляется BigInt64Array (пока спецификация не введена, поэтому не во всех браузерах, и скорость не мерял; ну и конечно же предложенный TypedArray.prototype.set лучше).
несколько лет назад (еще до появления asm.js) сравнивал скорость копирования, и на некоторых браузерах UInt32Array был быстрее, чем Float64Array.

wibuhu Добавили бы ремарку рядом с этим примером, что его нельзя использовать.

Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории