Почему тормозят 500 циклов, в чем причина и как это оптимизировать?

Так случилось что понадобился большой скрипт, чтобы замедлить работу браузера, потом я пошел дальше и
проверил как с этой задачей справятся другие языки. Итак, я использовал такой код:
500 циклов, каждый 125 000 000 итераций, в теле инструкция: result = n * 3 / 2.
let result;
let i;

for (i = 0; i < 125000000; i++) {
	result = i * 3 / 2;
}
for (i = 0; i < 125000000; i++) {
	result = i * 3 / 2;
}
for (i = 0; i < 125000000; i++) {
	result = i * 3 / 2;
}
// еще 497 аналогичных цикла...

Тут приведен JS код, в других языках конструкция аналогична. Результат меня весьма удивил...

PHP - провал *.
C# - провал *.
С - 163 секунды.
С++ - 150 секунд.
JS (Node) - 56 секунд.

Запускал под ОС Windows 10.
* операция длилась более 15 минут, надоело ждать завершения - убил процесс.

Опытные товарищи, подскажите, каким образом нода могла оказаться быстрее C и С++ и
почему C# с PHP вообще "забуксовали"?
Это может быть связанно с не оптимизированным доступом к памяти в случае нативного кода?
  • Вопрос задан
  • 1919 просмотров
Решения вопроса 3
vt4a2h
@vt4a2h
Senior software engineer (C++/Qt/boost)
Скомпилируйте C++ в релизом режиме со всеми оптимизациям.
Ну и godbolt зайдите и посмотрите, во что ваш код превратится под разными компиляторами. Там циклов скорее всего даже не будет.
Ответ написан
@deliro
Агрессивное программирование
Компилятор/интерпретатор может удалять циклы, если они не делают ничего. В твоём случае первые 499 перезатирают result раз за разом. Циклы оптимизатор может сворачивать в арифметическую/геометрическую прогрессии, если это возможно. Также, все 500 циклов вообще могут быть удалены, т.к. переменная result после циклов не используется. Именно это сделает gcc с опцией -O2 или -O3 (пруф: https://godbolt.org/z/JsAc0C )

Чтобы оптимизатор не оптимизировал, нужно:
1) В цикле суммировать переменную, да так, чтобы это не было похоже на прогрессию. Например, Math.random()
2) Переменную, которая использовалась в цикле, нужно использовать (например, return)
Ответ написан
@Mercury13
Программист на «си с крестами» и не только
Вот такой код
#include <iostream>

using namespace std;

int main()
{
    size_t i, result, sum;

    for (int q = 0; q < 500; ++q) {
        for (i = 0; i < 125000000; ++i) {
          result = i * 3 / 2;
          sum += result;
        }
    }
    std::cout << sum << std::endl;
    return 0;
}

в отладке 122 секунды, в -O2 закончился за 25 секунд. Если отказаться от переменной sum, компилятор замечает, что цикл ни к чему, и выполняет мгновенно. Так что дело, вероятно, в оптимизациях.
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
OnYourLips
@OnYourLips
Производительность языков определяется не синтетическими тестами, а реальными задачами.

На синтетическом тесте без четких требований к компилятору и среде выполнения вы можете получить абсолютно произвольные результаты.
Вы их и получили. Это абсолютно нормально.
Ответ написан
@MrDeadToast
Я не знаю как ты тестировал C#

Код: https://gist.github.com/Keroosha/3ccd0dc26f7c3d984...
Фулл скрина с BenchmarkDotNet: https://i.imgur.com/GUxn0RP.png
GUxn0RP.png

Получилось 20 секунд в Release сборке, информация об окружении есть на скрине
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через TM ID
Похожие вопросы