Почему два вызова метода string.charCodeAt () быстрее, чем один с другим в никогда не достижимом, если? - PullRequest
0 голосов
/ 13 января 2019

Я обнаружил странное поведение в nodejs / chrome / v8. Кажется, этот код:

var x = str.charCodeAt(5);
x = str.charCodeAt(5);

быстрее этого

var x = str.charCodeAt(5); // x is not greater than 170
if (x > 170) {
  x = str.charCodeAt(5);
}

Сначала я, хотя, может быть, сравнение стоит дороже, чем фактический второй вызов, но когда содержимое внутри блока if не вызывает str.charCodeAt(5), производительность такая же, как и для одного вызова.

Почему это? Мое лучшее предположение - v8 оптимизирует / деоптимизирует что-то, но я понятия не имею, как точно понять это или как предотвратить это.

Вот ссылка на jsperf, которая хорошо демонстрирует это поведение, по крайней мере, на моей машине: https://jsperf.com/charcodeat-single-vs-ifstatment/1

jsperf


Справочная информация : Причина, по которой я обнаружил это, потому что я пытался оптимизировать чтение токена внутри babel-parser .

Я тестировал, и str.charCodeAt() в два раза быстрее str.codePointAt(), поэтому я могу заменить этот код:

var x = str.codePointAt(index);

с

var x = str.charCodeAt(index);
if (x >= 0xaa) {
  x = str.codePointAt(index);
}

Но второй код не дает мне никакого преимущества в производительности из-за описанного выше поведения.

1 Ответ

0 голосов
/ 14 января 2019

V8 разработчик здесь. Как указывает Берги: не используйте микробенчмарки для обоснования таких решений, потому что они будут вводить вас в заблуждение.

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

Когда я копирую четыре фрагмента в небольшой автономный файл для локального исследования, я вижу совершенно разные результаты производительности. Какие из них ближе к вашему реальному варианту использования? Без понятия. И это делает бессмысленным дальнейший анализ того, что здесь происходит.

Как правило, ветви работают медленнее, чем прямолинейный код (на всех процессорах и на всех языках программирования). Таким образом (исключая устранение мертвого кода и другие ловушки микробенчмаркинга в стороне), я не удивлюсь, если на самом деле «двойной» случай окажется быстрее, чем любой из двух «если». Тем не менее, вызов String.charCodeAt вполне может быть достаточно тяжелым, чтобы компенсировать этот эффект.

...