От чего зависит «скорость» языка программирования?


38

Предположим, что программа написана на двух разных языках, пусть это будет язык X и язык Y, если их компиляторы генерируют один и тот же байт-код, почему я должен использовать язык X вместо языка Y? Что определяет, что один язык быстрее, чем другой?

Я спрашиваю об этом, потому что часто вы видите, что люди говорят что-то вроде: «C - самый быстрый язык, ATS - это язык, быстрый как C». Я пытался понять определение «быстрый» для языков программирования.


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

5
Языки - это просто понятие, которое используют для написания программ, поэтому вы не можете говорить о скорости языка.
Юхо

1
@ Рафаэль Я чувствую, что это не по теме, неясно и слишком широко. Хотя эта тема лучше подходит для разработки программного обеспечения , я подозреваю, что она будет закрыта как "слишком широкая".
Дэвид Ричерби

2
Реализация в сторону, «скорость» неоднозначно, существуют различные скорости для реализации, компиляции, выполнения и отладки, и вы вообще собираетесь торговать с некоторых для других ( в противном случае мы бы все использовать на языке программирования)
Ник T

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

Ответы:


23

Есть много причин, по которым можно выбрать язык X вместо языка Y. Такими причинами могут быть читаемость программы, простота программирования, переносимость на многие платформы, наличие хороших сред программирования. Тем не менее, я буду рассматривать только скорость выполнения, как указано в вопросе. Вопрос, похоже, не учитывает, например, скорость разработки.

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

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

Тем не менее, проблема относительной скорости языков является давней, начиная с первых компиляторов.

В течение многих лет, в те ранние времена, профессионалы считали, что рукописный код работает быстрее, чем скомпилированный код. Другими словами, машинный язык считался более быстрым, чем языки высокого уровня, такие как кобол или фортран. И это было быстрее и обычно меньше. Языки высокого уровня все еще развивались, потому что их было намного проще использовать для многих людей, которые не были компьютерными учеными. У стоимости использования языков высокого уровня даже было имя: коэффициент расширения, который мог бы касаться размера сгенерированного кода (очень важная проблема в те времена) или количества фактически выполненных инструкций. Концепция была в основном экспериментальной, но сначала соотношение было больше 1, поскольку по современным стандартам компиляторы проделали довольно простую работу.

Таким образом, машинный язык был быстрее, чем, скажем, Fortran.

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

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

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

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

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

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

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

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

Или, например, некоторые языки являются узкоспециализированными, например языки описания синтаксиса, используемые для программирования синтаксических анализаторов. Генератор синтаксический анализатор не что иное, как компилятор для таких языков. Конечно, он не является полным по Тьюрингу, но эти компиляторы чрезвычайно хороши для своей специальности: создание эффективных программ синтаксического анализа. Область знаний ограничена, методы оптимизации могут быть очень специализированными и очень точно настроенными. Эти генераторы синтаксических анализаторов обычно намного лучше, чем то, что можно получить, написав код на другом языке. Есть много узкоспециализированных языков с компиляторами, которые производят отличный и быстрый код для ограниченного класса задач.

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

Другой важный момент - это просто наличие эффективных библиотек для программируемых тем.

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

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


Спасибо. Это что-то вроде этого. Я искал. Трудно было найти материал для предмета. Это достаточно прояснилось.
Родриго Валенте

@ RodrigoAraújoValente Спасибо, вы можете посмотреть на этот вопрос . Экстремистская точка зрения заключается в том, что компилятор для языка L может просто связать интерпретатор для L с исходным кодом программы, ничего не делая. Тогда вы можете добиться большего успеха, пытаясь оптимизировать вычисления пакета (частичная оценка). Чем больше вы оптимизируете и тем быстрее будет ваш язык. Тогда возникает вопрос: что может помочь вам оптимизировать? Ответы могут включать хорошее знание специализированной предметной области, помощь программиста, сложный анализ и т. Д.
babou

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

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

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

16

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

Интерпретируемые языки Некоторые языки интерпретируются, а не компилируются , например, Python, Ruby и Matlab. Это означает, что код Python и Ruby не компилируется в машинный код, а интерпретируется на лету. Можно скомпилировать Python и Ruby в виртуальную машину (см. Следующий пункт). Смотрите также этот вопрос . Интерпретируется, как правило, медленнее, чем скомпилированный код по разным причинам. Не только сама интерпретация может быть медленной, но и труднее выполнять оптимизацию. Однако, если ваш код тратит большую часть времени на библиотечные функции (в случае Matlab), производительность не пострадает.

Виртуальная машина Некоторые языки компилируются в байт-код , изобретенный «машинный код», который затем интерпретируется. Наиболее существенными примерами являются Java и C #. Хотя байт-код может быть преобразован в машинный код на лету, код, вероятно, будет работать медленнее. В случае Java для переносимости используется виртуальная машина. В случае C # могут быть и другие проблемы, такие как безопасность.

Накладные расходы Некоторые языки обменивают эффективность на безопасность. Например, некоторые версии Pascal проверяют, что вы не обращаетесь к массиву за пределами. Код C # является «управляемым», и это имеет свою стоимость. Другой распространенный пример - сборка мусора, которая экономит время программиста, но не так эффективна, как управление памятью. Существуют и другие источники накладных расходов, такие как инфраструктура для обработки исключений или для поддержки объектно-ориентированного программирования.

* На самом деле, в настоящее время высокопроизводительные системы также выполняют код на графических процессорах и даже на ПЛИС.


Итак, если мне нужно больше производительности, я должен пойти на скомпилированные языки? А насчет парадигм? Есть причина выбирать функционал вместо oop, или наоборот?
Родриго Валенте

Ваше замечание о сборке мусора немного упрощено. Это не всегда разрешимо статически, когда выделенная память больше не используется. Даже когда это разрешимо, это может быть очень трудно определить без ошибок. Следовательно, GC иногда необходим и часто более безопасен (например, проверка границ массива). Кроме того, это может быть объединено с явным выпуском.
Бабу

@ RodrigoAraújoValente Зависит. Дрянной код часто компилируется в дрянной код. Возможно, код, который вы можете написать на Python, на самом деле быстрее, чем код, который вы можете написать на C.
Рафаэль

nit: как объясняется вопросом, с которым вы связались, python фактически не интерпретируется «на лету» :)
Eevee

Ни один из языков, которые вы упоминаете в интерпретируемом разделе, не интерпретируется на лету. Python скомпилирован в байт-код, Ruby был скомпилирован в AST, но я считаю, что теперь скомпилирован в байт-код. Matlab, я полагаю, сейчас JIT скомпилирован. На самом деле, я не знаю какой-либо нешевой языковой реализации, которая интерпретирует вещи на лету, а не, по крайней мере, компилирует их в какое-то виртуальное представление машины.
Уинстон Эверт

5

Есть разные факторы для выбора X вместо Y, например

  • Простота обучения
  • Простота понимания
  • Скорость развития
  • Помогите с введением правильного кода
  • Производительность скомпилированного кода
  • Поддерживаемые платформы
  • портативность
  • Пригодный для целей

Некоторые языки подходят для разработки бизнес-проектов, таких как C # или Python, но, с другой стороны, некоторые из них хороши для системного программирования, например C ++.

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


1
Итак, как определить производительность скомпилированного кода? Это в основном то, что заставило меня сделать этот вопрос.
Родриго Валенте

6
Этот ответ, безусловно, имеет хороший совет, но я не понимаю, как он отвечает на вопрос, который касается скорости как фактора выбора языка.
Бабу

@ RodrigoAraújoValente Они могут даже не быть скомпилированным кодом (если ваш язык интерпретируется).
Рафаэль

1
Вы можете добавить «Хорошие библиотеки» и «Хорошие инструменты».
Рафаэль

@ RodrigoAraújoValente Вы запускаете его и профилируете.
Кайл

2

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

Преобразование из C в сборку очень "мелкое", так как оно близко к одному, но оно более читаемо. Однако он имеет много слоев над ним благодаря стандартным библиотекам для улучшения переносимости. Не так много вещей, которые компилятор должен был бы сделать, чтобы добраться до ассемблерного кода, и более сильные оптимизации обычно вносят изменения, специфичные для машины.

C ++ добавляет более богатый язык. Однако, поскольку язык добавляет столько сложности, компилятору становится все труднее создать оптимальный код для платформы.

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

Тогда у нас есть те между Как правило, они имеют уровень виртуальной машины, оптимизированный для платформы. И компилятор создаст код для виртуальной машины для выполнения. Иногда это происходит одновременно, как perl, pascal, ruby ​​или Python. Или в несколько этапов, как Java.

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

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


Исторически, C был разработан, чтобы позволить легкий перевод в машинный код. Однако для все большей степени превращение C в эффективный код C требует, чтобы компилятор выяснил, что программист пытался сделать, а затем перевел это намерение в машинный код. Например, исторически машинный код, эквивалентный тому, который был *p++=*q++;бы на многих машинах, был быстрее, чем array1[i]=array2[i];на многих процессорах, но часто происходит обратное, и поэтому компиляторы могут в конечном итоге преобразовать первый стиль кода во второй - вряд ли это «поверхностное» преобразование.
суперкат

Обычно, если вы это сделаете, -O0это не приведет к оптимизации. Оптимизация - это бонус, который вы получаете с компилятором, но сам по себе язык может переводить почти один в один для сборки.
Архимед Траяно

2

Вопрос, который еще не был упомянут, заключается в том, что в некоторых языках многократное выполнение одного и того же фрагмента кода всегда будет выполнять одну и ту же последовательность действий; Таким образом, компьютеру нужно только один раз определить, что должен делать раздел кода. Одним из основных преимуществ «использования строгого» диалекта JavaScript является то, что, как только механизм JavaScript выясняет, что делает фрагмент кода, он может использовать эту информацию при следующем запуске; без «строгого использования» это невозможно.

Например, в отсутствие «используйте строгий» фрагмент кода, подобный следующему:

function f() { return x; }

может вернуть переменную X в контексте непосредственного вызова, если она есть, или переменную X из внешнего контекста вызова, или она может вернуться Undefined. Хуже, в цикле вроде:

for (i=0; i<40; i+=1) { g(i); }

у движка JavaScript нет возможности узнать, что g()может с этим сделать i[или с gсамим собой. Поскольку gили iвполне может быть законно преобразовано iв строку, движок JavaScript не может просто использовать числовое сложение и числовое сравнение в цикле, а должен при каждом проходе цикла проверять, чтобы убедиться, что какой-либо из вызовов функции что-либо сделал iили g, В противоположность этому, на «строгом» [несколько нормальном] диалекте движок JavaScipt может исследовать приведенный выше код и знать, что при каждом прохождении цикла будет использоваться одна и та же числовая переменная и вызываться одна и та же функция. Таким образом, потребуется только определить iи функционироватьg один раз, вместо того, чтобы искать их при каждом прохождении цикла - это значительная экономия времени.


2

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

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

Хотя компиляторы сегодня очень сложны, они все еще не эффективны, как это могут делать лучшие программисты на ассемблере.

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

Поэтому для меня язык X быстрее, чем язык Y (во время выполнения), если для определенного фрагмента кода машинный код X короче, чем Y.


Сборка полностью качается. Требуется настоящий художник, чтобы выиграть у лучших компиляторов.
Йохан - восстановить Монику

1

На этот вопрос сложно ответить однозначно, потому что он настолько сложный и многомерный (это почти как, например, сравнение марок автомобилей по разным критериям), но существуют новые научные исследования, в том числе превосходное хранилище кодов, известное как код Rosetta ( обзор Википедии ). Этот опрос 2014 года, проведенный Nanz и Furia, изучает этот вопрос довольно точно и научно, основываясь на следующих типичных критериях и редком количественном анализе типично субъективных качеств кода. Аннотация содержит некоторые объективно-обоснованные выводы и обобщения. (Надеюсь, что другие исследования, основанные на этих результатах, могут быть проведены в будущем.)

  • RQ1. Какие языки программирования делают для более краткого кода?

  • RQ2. Какие языки программирования компилируются в меньшие исполняемые файлы?

  • RQ3. Какие языки программирования имеют лучшую производительность во время выполнения?

  • RQ4. Какие языки программирования используют память более эффективно?

  • RQ5. Какие языки программирования менее подвержены сбоям?

Аннотация. Иногда дебаты о языках программирования носят скорее религиозный, чем научный характер. Вопросы о том, какой язык является более кратким или эффективным, или делает разработчиков более продуктивными, обсуждаются с энтузиазмом, и их ответы слишком часто основаны на анекдотах и ​​необоснованных убеждениях. В этом исследовании мы используем в значительной степени неиспользованный исследовательский потенциал Rosetta Code, хранилища кода решений общих задач программирования на разных языках, которое предлагает большой набор данных для анализа. Наше исследование основано на 7 087 программных решениях, соответствующих 745 задачам на 8 широко используемых языках, представляющих основные парадигмы программирования (процедурный: C и Go; объектно-ориентированный: C # и Java; функционал: F # и Haskell; сценарии: Python и Ruby). Наш статистический анализ показывает, в частности, что: функциональные языки и языки сценариев более лаконичны, чем процедурные и объектно-ориентированные языки; C трудно превзойти, когда речь идет о необработанной скорости на больших входах, но различия в производительности по сравнению с входами среднего размера менее выражены и позволяют даже интерпретируемым языкам быть конкурентоспособными; скомпилированные языки со строгой типизацией, где во время компиляции может быть обнаружено больше дефектов, менее подвержены сбоям во время выполнения, чем интерпретированные или слабо типизированные языки. Мы обсуждаем последствия этих результатов для разработчиков, разработчиков языков и преподавателей. там, где во время компиляции можно обнаружить больше дефектов, они менее подвержены сбоям во время выполнения, чем интерпретированные или слабо типизированные языки. Мы обсуждаем последствия этих результатов для разработчиков, разработчиков языков и преподавателей. там, где во время компиляции можно обнаружить больше дефектов, они менее подвержены сбоям во время выполнения, чем интерпретированные или слабо типизированные языки. Мы обсуждаем последствия этих результатов для разработчиков, разработчиков языков и преподавателей.


0

Компьютерные языки - это просто абстракция команд, объясняющих компьютеру, что делать.

Вы даже можете писать на компьютерном языке Pythonи компилировать его с помощью компилятора C (cython).

Учитывая это, скорость компьютерных языков не может сравниться.

Но вы можете сравнить компиляторы для одного и того же языка до некоторой степени. Например, GNU Cкомпилятор против Intel Cкомпилятора. (Поиск по тесту компилятора)


2
Если вы хотите прокомментировать вопрос, пожалуйста, используйте поле для комментариев, а не ваш ответ. Обратите внимание, что это компьютерный обмен стеками, а компьютерные науки - это не программирование, равно как литература - это не обработка текстов. Вопросы программирования в прямом эфире по программной инженерии или переполнению стека .
Дэвид Ричерби,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.