Большое обзорное тестирование языков программирования

Недавно очередной раз отработал со студентам 2-го курса 2-семестровую дисциплину «Алгоритмические языки». Обзорно рассмотрели несколько дюжин языков программирования. Один из студентов, Вадим Шукалюк, захотел получше с ними познакомиться, получить более четкое представление о каждом из них. Посоветовал ему провести небольшое исследование. Чем и увлёк. Предлагаю свой отчёт по проделанной за несколько месяцев вместе с ним работе.

У каждого языка программирования есть свои достоинства и недостатки. Одна из важнейших характеристик транслятора с любого языка — это скорость исполнения программ. Очень трудно или даже невозможно получить точную оценку такой скорости исполнения. Ресурс http://benchmarksgame.alioth.debian.org/ предлагает игровую форму для проверки такой скорости на разных задачах. Но число языков, представленных на этом ресурсе, довольно невелико. Предельную ёмкость стека, критическую величину для рекурсивных вычислений проверить проще, но она может меняться в разных версиях транслятора и быть зависимой от системных настроек.

Тестировались следующие трансляторы: си (gcc, clang, icc), ассемблер (x86, x86-64), ява (OpenJDK), паскаль (fpc), яваскрипт (Google Chrome, Mozilla Firefox), лисп (sbcl, clisp), эрланг, хаскель (ghc, hugs), дино[1], аук (gawk, mawk, busybox), луа, рубин, бейсик (gambas, libre office), питон-2, пи-эйч-пи, постскрипт (gs), пролог (swipl, gprolog), перл, метапост, ТEХ, тикль, бэш. Исследовались как собственно скорость исполнения нескольких небольших, но трудоёмких алгоритмов, так и:

  • качество оптимизации некоторых трансляторов;
  • особенности при работе с процессорами Intel и AMD;
  • предельное число рекурсивных вызовов (ёмкость стека).


В качестве первой задачи, на которой тестировались все трансляторы, выбран расчёт числа Фибоначчи двойной рекурсией согласно определению: числа с номерами 1 и 2 — это единицы, а последующие — это сумма двух предыдущих. Этот алгоритм имеет несколько привлекательных особенностей:

  1. Если время расчета n-го числа t, то (n+1)-го — t*φ, где φ — это золотое сечение равное (√5+1)/2;
  2. Само вычисляемое n-e число равно округлённой до ближайщего целого величине φn/√5;
  3. Расчёт fib(n+1) требует n-й вложености вызовов.

Первая особенность позволяет за небольшое время протестировать трансляторы, скорости работы которых различаются в сотни тысяч раз. Вторая особенность позволяет быстро проверять правильность расчетов. Третья особенность теоретически позволяет исследовать ёмкость стека, но из-за того, что расчет при n > 50 становится очень медленным даже на суперкомпьютере, практически использовать эту особенность не представляется возможным.

В следующей таблице 1 во второй колонке указывается название языка, название компилятора и его версия и, если использовалась, опция оптимизации генерируемого кода. В третьей колонке приводится относительное время вычисления на процессоре AMD Phenom II x4 3.2 ГГц. Тесты проводились и на AMD FX-6100 на такой же частоте, но их результаты мало отличаются от приведённых. За единицу принято время вычисления на языке бэш, таким образом, расчёт на эрланге примерно в 20000 раз быстрее бэш. В 4-й колонке приводится относительное время вычисления на процессоре Intel Core i3-2100 3.1 ГГц. Так как сравнение процессоров не было целью исследования, часть трансляторов не были протестированы на платформе Intel. В пятой — оценка сверху (точность 10%) максимального числа рекурсивных вызовов, поддерживаемых транслятором при вычислении ack(1,1,n) на компьютере с 8 Гб оперативной памяти c размером системного стека (ulimit -s) 8192 КБ. Некоторые трансляторы используют собственные настройки, которые определяют размер используемого стека — всегда используются значения по умолчанию для выбранной версии транслятора. Измерения проводились в системе Linux, но их результаты не должны меняться при переходе к другой ОС. Данные отсортированы по 3-й колонке. Все исходники можно посмотреть здесь.

Табл 1.
N Язык AMD Intel Стек
1 C/C++ (gcc 4.7.2, -O5) 354056 493533 790000
2 C/C++ (clang 3.0-6.2, -O3) 307294 270000
3 C/C++ (icc 14.0.3, -fast) 250563 232665 530000
4 Assembler x86-64 243083 271443 350000
5 Assembler x86 211514 301603 700000
6 Java (OpenJDK 1.7.0_25) 186401 239659 8000
7 Pascal (fpc 2.6.0, -O3) 170604 186401 180000
8 C/C++ (gcc 4.7.2, -O0) 159672 173261 180000
9 C/C++ (clang 3.0-6.2, -O0) 146726 110000
10 C/C++ (icc 14.0.3, -O0) 136862 156602 530000
11 Javascript (Mozilla Firefox 25) 121979 4200
12 Javascript (Google Chrome 31) 92850 10000
13 Lisp (sbcl 1.0.57) 54925 51956 31000
14 Erlang (5.9.1) 19845 18589 предела нет
15 Haskell (ghc 7.4.1, -O) 18589 22946 260000
16 Awk (mawk 1.3.3) 6621 6306 44000
17 Lua (5.2) 6420 7075 150000
18 Ruby (1.9.3) 5297 6969 6600
19 Dino (0.55) 5024 6420 190000
20 Basic (Gambas 3.1.1) 3968 4373 26000
21 Python (2.7.3) 3678 4013 1000
22 PHP (5.4.4) 2822 3720 предела нет
23 Awk (gawk 4.0.1) 2648 2547 предела нет
24 Postscript (gs 9.05) 2355 3246 5000
25 Prolog (swipl 5.10.4) 1996 2407 2300000
26 Perl (5.14.2) 1516 1670 предела нет
27 Prolog (gprolog 1.3.0) 1116 1320 120000
28 Lisp (clisp 2.49) 998 1023 5500
29 Awk (busybox 1.20.2) 981 1113 18000
30 TEX (3.1415926) 239 333 3400
31 Metapost (1.504) 235 470 <4100
32 Tcl (8.5) 110 123 1000
33 Haskell (hugs 98.200609.21) 82 121 17000
34 Basic (LibreOffice 3.5.4.2) 20 35 6500
35 bash (4.2.37) 1 0,77 600


В качестве второй задачи выбрана функция Аккермана в форме, когда к ней сводятся все арифметические операции, т. е. ack(1,x,y)=x+y, ack(2,x,y)=x*y, ack(3,x,y)=xy, ack(4,x,y) — тетрация x и y и т. д.



Эта функция с ростом n растёт очень быстро (число ack(5,5,5) настолько велико, что количество цифр в порядке этого числа многократно превосходит количество атомов в наблюдаемой части Вселенной), но считается очень медленно. Последнее свойство теоретически удобно для тестирования быстродействия. Однако, расчет этой функции требует значительного числа рекурсивных вызовов и большинство тестируемых языков оказалось не в состоянии их поддерживать для вычислений, имеющих заметную длительность. Известно, что вычисление этой функции нельзя свести к итерации. Расчет по этой задаче позволил исследовать максимальную ёмкость стека исследуемых языков: расчёт ack(1,1,n-1) требует n-й вложенности вызовов и очень быстр. В следующей таблице 2 представлены результаты расчета пентации ack(5,2,3), для тех языков, стек которых смог его (вложенность вызовов 65539) выдержать. За единицу скорости выбрано время работы gcc с опцией -O5, т. е. php примерно в 420 раз медленнее.

Табл 2.
gcc -O5 1
asm x86 2.15
icc -fast 2.18
asm x86-64 2.36
clang -O3 2.76
fpc -O3 4.44
gcc -O0 7.75
icc -O0 8.36
clang -O0 9.64
Erlang 18.51
ghc -O 50.18
lua 122.55
php 423.64
gawk 433.82
swipl 766.55
dino 915.64


Идея использовать приведённые две задачи позаимствована из труда Б. В. Кернигана и Р. Пайка «Unix — универсальная среда программирования», где она была использована для тестирования языка hoc[2].

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

Время измерялось стандартной командой time, а тогда, когда это было невозможно (яваскрипт, офисный бейсик) использовались встроенные в язык средства.

По результатам исследования сделаны следующие выводы, некоторые из которых оказались несколько неожиданными:

  1. Скорость работы программ на ассемблере может быть более 50% медленнее, чем программ на си/си++, скомпилированных с максимальной оптимизаций;
  2. Скорость работы виртуальной ява-машины с байт-кодом часто превосходит скорость аппаратуры с кодами, получаемыми трансляторами с языков высокого уровня. Ява-машина уступает по скорости только ассемблеру и лучшим оптимизирующим трансляторам;
  3. Скорость компиляции и исполнения программ на яваскрипт в популярных браузерах лишь в 2-3 раза уступает лучшим трансляторам и превосходит даже некоторые качественные компиляторы, безусловно намного (более чем в 10 раз) обгоняя большинство трансляторов других языков сценариев и подобных им по скорости исполнения программ;
  4. Скорость кодов, генерируемых компилятором языка си фирмы Intel, оказалась заметно меньшей, чем компилятора GNU и иногда LLVM;
  5. Скорость ассемблерных кодов x86-64 может меньше, чем аналогичных кодов x86, примерно на 10%;
  6. Оптимизация кодов лучше работает на процессоре Intel;
  7. Скорость исполнения на процессоре Intel была почти всегда выше, за исключением языков лисп, эрланг, аук (gawk, mawk) и бэш. Разница в скорости по бэш скорее всего вызвана разными настройками окружения на тестируемых системах, а не собственно транслятором или железом. Преимущество Intel особенно заметно на 32-разрядных кодах;
  8. Стек большинства тестируемых языков, в частности, ява и яваскрипт, поддерживают только очень ограниченное число рекурсивных вызовов. Некоторые трансляторы (gcc, icc, ...) позволяют увеличить размер стека изменением переменных среды исполнения или параметром;
  9. В рассматриваемых версиях gawk, php, perl, bash реализован динамический стек, позволяющий использовать всю память компьютера. Но perl и, особенно, bash используют стек настолько экстенсивно, что 8-16 ГБ не хватает для расчета ack(5,2,3). В версии 5.4.20 php стек оказался ограниченным примерно 200000 вызовов.


В заключении несколько слов от студента, начинающего осваивать искусство программирования.

Чтобы написать программы для требуемых расчётов на любом языке, необходимо в первую очередь понять как в конкретном языке объявляются переменные, как построить конструкцию типа if-else и как организовать рекурсию. Свою работу я начал с простого языка Pascal, так как на тот момент знал его лучше всех. После паскаля, я взялся за C, Java и Dino, так как их синтаксисы примерно похожи. С оказался довольно интересным, простым, и в то же время с интуитивно понятными операторами. Ява показался менее удобным, чем си/си++ — надо писать много не относящегося к делу, такого, что могло бы быть взято по умолчанию. Также напряг момент необходимости одинаковости имён класса и файла. От Haskell остались только положительные эмоции. Удобный, понятный и мощный. PHP, язык для разработки веб-приложений, очень похож на С: можно просто вставить код на си с минимальными изменениями и все будет работать так, как надо. Erlang похож по синтаксису на Haskell и немного на Prolog. Тоже довольно приятный и понятный язык, никаких трудностей не возникло. Cинтаксис JavaScript похож на синтасис Java или C. Visual Basic как в офисном, так и GAMBAS исполнении имеет несколько угловатый и неудобный синтаксис, но в целом, с ним было не очень трудно. Затем, после приобретения знаний о базом синтаксисе С и Java, получилось довольно быстро написать код на Python, так как Python схож с С. Никаких проблем не возникло с Lua и его довольно мощными и гибкими конструкциями. У awk также схожее строение с С, довольно быстро удалось его осилить. С лиспом возникли некоторые трудности, как у человека, который до этого изучал С-подобные языки, например, с базовым пониманием префиксной записи. Которая после небольших затрат на освоения, показалась очень удобной, логичной и красивой. После, я перешел на язык логического программирования Prolog, который оказался специфичным, но очень интересным и фундаментальным. Ruby — язык с мощной поддержкой объекто-ориентированного программирования и с очень красивым ярко-красным рубином на иконке оказался превосходным языком: никаких лишних скобок, точек с запятой и прочих ненужных знаков. Один из наиболее запомнившихся. Хотя питон, если не считать конструкций ООП, не менее лаконичен. Perl — хоть и носит название «жемчужина», символом языка является верблюд, что видимо является отсылкой к тому, что верблюд не слишком красивое, но очень выносливое животное, способное выполнять тяжёлую работу. После Ruby опять ставить доллары, скобки и точки с запятой было не очень приятно. Синтаксис местами похож на синтаксис языка терминальной оболочки Bash. Затем я взялся за ассемблер. Здесь были определенные трудности и необходимость понимания работы процессора и его регистров. Удивлению не было предела, когда оказалось, что С справляется с расчётами быстрее чем ассемблер, машинный код! Проблем не возникло с Bash, хоть там и нужно ставить много долларов, а при расчётах и скобок. Язык Metapost/Metafont вызвал некоторые проблемы — там поддерживаются только числа, не большие 4096. Хотя его синтаксис вполне традиционен. У тикля (TCL) тоже довольно традиционный синтаксис, но строчно-ориентированный — это и похожая на bash семантика поначалу очень сбивали с толку. Наиболее сложным показались PostScript. В этом языке синтаксис очень специфичен и без подготовки, интуитивно ничего написать не получится, поэтому пришлось изучать соответствующую литературу и начать тренироваться с самых простейших программок. PostScript был настоящим испытанием: написать двойную рекурсию постфиксной записью лишь при помощи стека, после привыкания ко всем инструментам и возможностям Ruby и C было проблематично. Писать и тестрировать на постскрипте функцию Аккермана, все равно что пытаться покрасить стену зубной щёткой. Но первое место по сложности определенно занимает TEX. Ничего более трудного я не встречал. И без прямой помощи преподавателя одолеть этот язык не получилось бы.

Любопытными оказались данные по размерам стека языков. Чем больше стек языка, тем больше вероятность, что он сможет справиться с функцией Аккермана. Но если программа на каком-то языке не смогла справиться с вычислением ack(5,2,3), это не значит что язык плохой и неудобный. Вполне вероятно, что этот язык мог создаваться для других полезных целей как, например, Metapost или Postscript.

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

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



[1] — Разработаный в России язык программирования. Ныне его автор — сотрудник компании Red Hat, работающий над совершенствованием коллекции компиляторов gcc. Последния версия дино выпущена в 2007 году.
[2] — Этот язык тоже был протестирован, показав результат по скорости между mawk и ghc.
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 59
  • +2
    Я думаю, что версию PHP стоит указывать везде (например добавить в первую таблицку), т.к. разница между 5.4 и 5.6 довольно значительная, а 5.4 и 7.0+Jit более чем ощущается: gist.github.com/dstogov/12323ad13d3240aee8f1#file-b-txt
    • +2
      Скрытый текст
      <?php
      $t = microtime(1);
      function fib ($n)
      {
          if ($n < 3) return 1;
          return fib($n - 1) + fib($n - 2);
      }
      echo fib(30) . "\n";
      echo microtime(1) - $t;
      


      PHP 5.4.34 (cli) (built: Oct 15 2014 21:58:00)
      > 0.32301807403564

      PHP 5.5.21 (cli) (built: Jan 21 2015 14:42:18)
      > 0.32501792907715

      PHP 5.6.6 (cli) (built: Feb 18 2015 16:02:19)
      > 0.30201697349548

      PHP 7.0.0-dev (cli) (built: Feb 5 2015 00:20:59) (без JIT)
      > 0.0590071105957
    • +21
      Скорость работы программ на ассемблере может быть более 50% медленнее, чем программ на си/си++, скомпилированных с максимальной оптимизаций;
      Однозначно ложное утверждение. Нет ничего быстрее ассемблера. Есть неотимально написанный софт. Одна из причин — слишком сильно отдаляешься от задачи которую выполняешь. Да и трудоёмкость оптимизации на ассемблере очень высока. Да чего далеко ходить. Дизассемблируйте то, что у вас получилось в результате компиляции. Вот вам 100% соответствующая по скорости программа на ассемблере.
      • +1
        Посмотрел на примере 64-битного кода (в Visual Studio). Когда сравнивал программу на C с простейшей программой на ассемблере, последняя была в 1.5 раза медленнее. Но в коде, сгенерированном компилятором, кроме самой функции было ещё много какой-то дополнительной информации. Судя по всему, она используется для inline подстановки ассемблерных функций (!).
        Действительно, когда я подставил код своей функции в неё саму на два уровня вложенности (т.е. получилось 7 копий кода), времена выполнения сравнялись. У компилятора возможностей для такой подстановки ещё больше.
        • +2
          При компиляции любых языков, кроме ассемблера, за оптимизацию отвечает компилятор. При программировании на ассемблере отвечает мозг человека! Вы не можете обогнать ассемблер из-за того, что ассемблер — это отображение языка процессора в человекопонятной форме. Любой другой код можно представить в виде ассемблерного кода, который будет один в один со скомпилированным результатом любого другого языка.
        • +2
          Вот интересная статья на эту тему: Beating the compiler
        • +19
          По результатам исследования сделаны следующие выводы, некоторые из которых оказались несколько неожиданными:

          1. Скорость работы программ на ассемблере может быть более 50% медленнее, чем программ на си/си++, скомпилированных с максимальной оптимизаций;



          Вот так потом и создают принципиально новые ОС и доказывают математически существование жизни после смерти.

          Это не скорость работы программ на ассемблере мендленнее (ведь всё в конце концов будет переведено в машинный код), это неумение оптимизировать вручную код на нём. Компиляторы могут читерить — частично разворачивать циклы и рекурсии, перестраивать последовательность операций для параллельного выполнения, правильно выравнивать данные. И на исходный алгоритм результат будет мало похож. И на грубину рекурсии это влияет. Компилятор заинлайнил 2 рекурсивных вызова — глубина рекурсии в 4 раза увеличилась. И производительность подскачила (чем меньше переходов, а уж тем более вызовов процедур, тем лучше). Но стек отстался прежним. Единственное приемущество, что компилятор всё это оптимизирует автоматически, может учитывать особенности конкретных моделей процессоров. А так — развернёте в ассемблере рекурсию на десяток уровней и получите совершенно другие результаты.

          Получилось отличное пособие о том, как не нужно делать бенчмарки.
          • 0
            Плюс сложность абстрагироваться от задачи и понимать не только алгоритм, то и где и как правильно использовать регистры процессора. При современном развитии компьютеров больше похоже на мазохизм. Хотя, в некоторых случаях, может резко поднять производительность.
            • 0
              А что вам не понравилось? Они _могут_ быть медленнее. Если плохо оптимизированы. А могут и не быть, в противном случае.
              • –1
                То, что это утверждение верно для любой пары языков. Это тавтология. И на Python можно написать код, который будет быстрее кода на C++. Да даже на Bash можно. Можно и на ассемблере написать так, что он будет медленнее любого существуюшего языка. И без дополнительных условий утверждение чего-то подобного — демагогия.

                Давайте на примерах? У вас в распоряжении велосипед (исправный, без подвохов), а у меня лишь баллончик с освежителем воздуха. Мы не можем друг на друга взаимодействовать (вы меня не можете переехать, я вам мешать не могу). И мы с вами участвуем в гонке.
                Я утверждаю, что я вас обгоню. Причём это не зависит от дистанции, хоть тысячу киллометров. Я даже вам дам фору в пару километров, т.к. мне вас жаль. Старт и финиш у нас с вами одни.
            • +2
              Однако, расчет этой функции требует значительного числа рекурсивных вызовов и большинство тестируемых языков оказалось не в состоянии их поддерживать для вычислений, имеющих заметную длительность. Известно, что вычисление этой функции нельзя свести к итерации
              Известно? А как быть с теоремой об удалении рекурсии?
              • 0
                Надо всего лишь реализовать стек и цикл с условием выхода по пустоте стека ;) Под итерациями скорее всего имеется в виду алгоритм с константной памятью.
                • +1
                  Эта функция забавна тем, что в итеративном виде она оказывается ничуть не быстрее рекурсивного :) 11 лет назад её тоже для простых бенчмарков использовал.
                • +17
                  Большая проблема сравнения языков программирования в том, что составители тестов не знают и половины из них. В итоге получается сравнение сферических коней в вакууме.

                  К примеру, вот так должен выглядеть код на Haskell (и примерно так же на Erlang)

                  fib :: Integer -> Integer -> Int -> Int -> Integer
                  fib cur prev n ref
                   | n == ref = cur
                   | otherwise = fib (cur + prev) cur (n+1) ref
                  
                  fib' :: Int -> Integer
                  fib' = fib 1 1 2
                  main = interact $ unlines . map (show . fib'. read) .lines
                  


                  Этот код тратит на вычисление 700000го числа Фибоначчи примерно столько же времени, сколько оригинальный код на вычисление 39го.
                  • +1
                    Аналогично, код на Java измеряет хтуфту. Как и большая часть бенчмарков на яве. Измерять что-либо без прогрева, не указывая какая из версий jvm и в каком режиме используется — пустая трата времени тех, кто эти результаты потом читает.
                    • +4
                      Хоть я и не знаком с Haskell, но почти уверен, что вы привели алгоритм с одним рекурсивным вызовом вместо двух.
                      • –3
                        Конечно! Потому что любой нормальный человек не будет использовать алгоритм с двумя рекурсивными вызовами там, где можно использовать один.

                        Я сделал и другие оптимизации. К примеру, явное указание «родных» типов вместо используемых по умолчанию «длинных» чисел, ускоряет программу в 10 раз. Но проблема в том, что так все равно никто не пишет. А раз так никто не пишет, то и показывать такой тест будет непонятно что.
                        • +4
                          А смысл? Если я правильно понимаю задумку автора, то такой идиотский алгоритм вычисления чисел Фибоначчи выбран как раз потому, что он тяжело оптимизируется компилятором/транслятором/средой исполнения. Иначе и на других более императивных языках можно было просто цикл написать и все.
                          • 0
                            П.С. Против явного указания нативных типов данных ничего не имею ,)
                            • 0
                              Для языков более высокого уровня оптимизация компилятора более важна. Haskell точно так же не может оптимизировать двойную рекурсию как и Си, но в случае Haskell относительный выигрыш от оптимизации может быть больше. Беда в том, что в реальной жизни никто не оставит двойную рекурсию в Haskell, также как и в Си, так что непонятно, что же исходный тест проверяет.
                              • +2
                                Нам был продемонстрирован изощренный способ сравнить:
                                1) скорость вызова функции
                                2) максимальную глубину стека
                                Потому и выбрали такой алгоритм, чтобы рекурсия ничем ни во что не разворачивалась (хотя в случае C/C++ с -O3/5 на какую-то глубину оно все же инлайнилось, это видно, в частности, по разной глубине стека -O0 vs -O3/5).
                                • 0
                                  Скорость вызова сферических функций и сферическую глубину стека. Эти параметры слишком сильно зависят от сигнатары функции — количества переменных, способа их передачи. Глубина стека отлично настраивается, и никто не мешает использовать хоть всю оперативную память под стек.
                                  • +1
                                    Ну, функция не совсем сферическая, а вполне определенная с одним целочисленным параметром (правда, вы утверждаете, что в случае Haskell этот параметр не совсем целочисленный, а bigInt). И потом, я же не спорил с тем, что ценность данного сравнения несколько сомнительна, а просто указал на то, что в приведенной работе всюду использовался один и тот же алгоритм (неважно с какими целями), а вы его предложили поменять лишь для одного отдельного ЯП.
                      • +8
                        Посмотрел сорцы, немного смутило то, что в разных языках вычисляются разные члены последовательности.
                        Надеюсь, в в процессе теста это было поправлено?
                        fib 15
                        

                        fib(32)
                        

                        int k = 41;
                        

                        System.out.println(fibc(40));
                        


                        Ну и про то, что
                        Скорость работы программ на ассемблере может быть более 50% медленнее, чем программ на си/си++, скомпилированных с максимальной оптимизаций

                        я бы добавил «неоптимизированных» перед «программ на ассемблере» — статья это отлично показала :)
                        • –2
                          Все программы реализуют один и тот же алгоритм… Аргументы разные, так как скорости очень разные и ждать год пока бэш отсчитает 41-е число затруднительно. Если написать на ассемблере иначе, то будет другой алгоритм. Может уже есть оптимизирующие ассемблеры?
                        • НЛО прилетело и опубликовало эту надпись здесь
                          • +8
                            Где c#??
                          • +2
                            не хватает бенчмарка конкатенации строк и записи на диск =D http://geektimes.ru/post/247892/
                            • +1
                              Астрологи объявили неделю бенчмарков
                            • +1
                              С/С++ — король всех языков!
                            • НЛО прилетело и опубликовало эту надпись здесь
                              • НЛО прилетело и опубликовало эту надпись здесь
                                • НЛО прилетело и опубликовало эту надпись здесь
                                • 0
                                  от гугла сравнение было неплохое, жаль только оно старенькое
                                  • 0
                                    Как будто тут новенькое.
                                    Автор софт наверное по BBS собирал, у него PHP 5.4.4.
                                    • 0
                                      Всё бюджетное и софт и хард.
                                    • 0
                                      Новый гугл немного побыстрее.
                                    • +1
                                      замечание по форме: что бы цифровые показатели в таблице было легче и правильнее воспринимать, их нужно
                                      * выравнять по правому краю
                                      * привести к единому формату (например, во второй таблице вещественные значения все отобразить с одинаковым количеством знаков после запятой)
                                      * использовать моноширинный шрифт

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

                                      Что называется, «почувствуйте разницу» jsfiddle.net/og2xt0nb/ (обрамление и прочие стили добавьте по вкусу)

                                      • –1
                                        Очень благодарен, но первый блин…
                                      • +10
                                        Пожалуйста, не учите своих студентов таким «бенчмаркам».
                                        • 0
                                          А можете написать поконкретнее о том, что вам кажется не так? Студент просто честно всё закодировал и измерил. Слегка обработал факты…
                                          • +2
                                            Студент в данном случае сделал работу хорошо, но сделал ее так, как просили вы. А вы просили что-то невнятное.
                                            В комментариях выше уже было указано на некоторые недочеты и сомнительные моменты. В целом хочется отметить низкое качество методики. Проводить бенчмарки — мастерство, которое сильно зависит от языка и платформы. С этим тяжело справиться без специальных инструментов и знаний, особенно студенту, писавшему до этого только на Паскале.
                                            Почему вы не почитали про методику на указанном вами benchmarksgame.alioth.debian.org? Там есть полезные источники информации. Также советую погуглить особенности бенчмарков Java-кода. Это только та информация, которой я владею, но думаю, она применима ко многим языкам, работающим под управлением виртуальных машин. Отдельный разговор про динамический языки. Даже в случае компилируемых в нативный код языков все не просто: у Haskell, например, есть проблемы с производительностью, связанные с ленивыми вычислениями.
                                            Зачем вам тестировать глубину стека? Обычно это настраиваемый параметр. И придирка: зачем писать названия языков по-русски?
                                            • –3
                                              Почему «невнятное»? Поразбирался человек с разным способом выразить один алгоритм. В статье не раз написано, что ни на какую абсолютность претензий нет. Написали, что получилось. Может стоит перечитать статью?
                                              • +2
                                                Я читал, дело не в «абсолютности». Определитесь с целями: либо «Большое обзорное тестирование языков программирования» (что неправда), либо «Разные способы выразить один простой алгоритм». В последнем случае алгоритм подобран плохо: он слишком прост для оценки способов выражения на разных языках.
                                        • +2
                                          Хм… интересно, почему Вы считаете вычисление Фибонначи является репрезентативной метрикой оценки быстродействия кода, сгенерированного компилятором? Есть же «уставной» способ оценки — SPEC2000/2006.
                                          • 0
                                            Спасибо за работу. Несколько замечаний:

                                            1. Бенчмарк очень своеобразный, потому что не понятно, на что тут тратится больше времени: на вычисления или на собственно рекурсивыне вызовы. Надо было выбрать что-нибудь более вычислительное, типа вычисление Быстрого Преобразования Фурье или что-нибудь с матрицами.

                                            2. Бенчмарк неактуальный, так как таких строго вычислительно-рекурсивных задач очень мало в современном программировании. Раз в сто больше задач по общей обработке информации типа «создать массив на сто тысяч строк, отсортировать его, отфильтровать по какому-нибудь паттерну, поработать с такой же хэштаблицей из ста тысяч строк и т.п.»

                                            3. Ну и, конечно, многие языки имеют свои супероптимальные конструкции для типичных задач, про которые сразу и не узнаешь, если быстро пробежишься по основам языка «чисто чтобы тест быстренько написать».

                                            4. Жалко, что с тестах присутствуют совсем экзотические языки, но нет, например, таких, как Scala и Clojure (хотя они явно не для вычислений чисел Фибоначи были придуманы).
                                            • –1
                                              Затраты на вызов функции и величина стека. Это все, что тут измерялось.
                                              • +1
                                                Вы практически пересказали мою мысль, но другими словами. О том и речь, что в реальном программировании ни величина стека, ни затраты на вызов функции не являются критичными ни в малейшей мере. Но в начале статьи указано другое — что измерялась «скорость исполнения программ».
                                                • 0
                                                  Про вызов функции можно и поспорить. Хотя ситуации, когда его скорость является критичной, встречаются крайне редко. Мне такое встретилось один раз — когда обработчик данных строился как последовательный вызов очень маленьких функций, указатели на которые были записаны в массив (строившийся после того, как стал известен формат данных). Остальные варианты реализации этой обработки были ещё хуже.
                                                  • 0
                                                    Да там был натуральный полиморфизм, да еще и времени исполнения! ) Однако, есть миллион способов избежать очень большого кол-ва очень маленьких функций. И в реальных системах, скорее наоборот, есть большая проблема огромных и очень огромных функций.
                                              • НЛО прилетело и опубликовало эту надпись здесь
                                                • +1
                                                  Ага. И вообще любой язык программирования потом превратится в машинные инструкции, которые будет выполнять один и тот же процессор. Так какой смысл вообще что-то сравнивать? Все равны. 8-)
                                                  • НЛО прилетело и опубликовало эту надпись здесь
                                                    • 0
                                                      Было бы странно, если бы компиляторы с разным функционалом, разной стандартной библиотекой давали одинаковый итоговый байткод.
                                              • +2
                                                Как-то не совсем понятно, что хотел донести автор и какие выводы из всего этого должен сделать студент и прочитавшие.

                                                Если это попытка показать, как выглядят программы на разных языках, то задача для этого выбрана совсем уж простая. Чтобы «прочувствовать» язык, надо написать что-то покрупнее, например веб-сервис или игру. А потом сравнить, какой из языков больше подходит к какой нише (хотя это и так все знают).

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

                                                1) Почему реализация питона только одна, если уж сравнивать на скорость, то надо было включить ещё и pypy? Он очень шустрый и довольно хорошо совместим с CPython. Например, у меня 33-е число Фибоначчи после прогрева pypy считает в 3-4 раза быстрее CPython.
                                                2) Почему нет другого «гонщика» — luajit? У неё, например, в комплекте есть поддержка ffi, поэтому скорость на простых бенчмарках на уровне v8/java/pascal (у меня на машине у luajit и C почти одинаковое время).
                                                3) Даже если забыть, что такую древовидную рекурсию обычно не используют в жизни, а стараются заменить её на что-то более линейное), всё равно так код не пишут. Например, хоть я и не писал на перле, но помню, что там есть такая замечательная штука, как memoize. Из таблицы видно, что перл уступает, например, питону. Но если добавить пару строк…

                                                Но если добавить пару строк
                                                use Memoize;
                                                
                                                sub fib {
                                                  my $n = shift;
                                                  if ($n < 3) {return 1;}
                                                  return fib($n-1) + fib($n-2);
                                                }
                                                
                                                memoize('fib');
                                                
                                                print fib(33), "\n"
                                                


                                                Результаты:
                                                $ time perl fib.pl
                                                3524578
                                                
                                                real    0m3.437s
                                                user    0m3.427s
                                                sys     0m0.008s
                                                
                                                $ time perl fib-memo.pl
                                                3524578
                                                
                                                real    0m0.028s
                                                user    0m0.020s
                                                sys     0m0.008s
                                                
                                                


                                                Это быстрее, чем PyPy (0m0.453s), Luajit(0m0.063s), и С без оптимизации (0m0.040s),
                                                C -O3 одинаково.

                                                Т.е. прирост в скорости составил 122 раза!


                                                Но самое главное, что все эти выводы никак не применимы в реальной жизни. Никто не бросится переписывать всё с С на перл, потому что в бенчмарке они по скорости одинаковы. А вот для научных расчётов, например, люди любят использовать питон, несмотря на его неторопливость. Весь секрет в том, что на питоне там ничего не считается, это всего лишь удобная оболочка к фортрановским и сишным библиотекам.

                                                Сравнивать веб-серверы под нагрузкой, это одно, там хотя бы задача приближена к реальности. А в этом примере, на мой взгляд, нет ни смысла, ни пользы.
                                                • –3
                                                  хотя это и так все знают
                                                  Очень благодарен вам за внимание к публикации. Хотя почти уверен, что не все и не всё.

                                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.