Почему C так быстро, и почему другие языки не так быстро или быстрее?

при прослушивании подкаста StackOverflow jab продолжает придумывать, что" настоящие программисты "пишут на C, и что C намного быстрее, потому что он" близок к машине."Оставляя прежнее утверждение для другого поста, что особенного в C, что позволяет ему быть быстрее, чем другие языки? Или иначе: что мешает другим языкам компилироваться до двоичного кода, который работает так же быстро, как C?

30 ответов


нет ничего особенного в C. Это одна из причин, почему это быстро.

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

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

тем не менее, многие языки и платформы, такие как Java (с его Виртуальная Машина Java) и .NET (с его Общеязыковой средой выполнения) улучшили производительность на протяжении многих лет с такими адвентами, как just-in-time compilation которая производит машинный код байткод для достижения более высокой производительности.


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

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

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

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

код C может быть непереносимо.

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

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

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


Если вы тратите месяц, чтобы построить что-то на C, которое работает за 0,05 секунды, и я провожу день, написав то же самое на Java, и он работает за 0,10 секунды, то C действительно быстрее?

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

хотя компиляторы действительно очень умны, они еще не могут творчески придумать код, который конкурирует с алгоритмами ручного массажа (предполагая, что" руки " принадлежат хороший C программист).

Edit:

много комментариев по строкам "я пишу на C, и я не думаю об оптимизации."

но взять конкретный пример эту статью:

в Delphi я мог бы написать следующее:

function RemoveAllAFromB(a, b: string): string;
var
  before, after :string;
begin
  Result := b;
  if 0 < Pos(a,b) then begin
    before := Copy(b,1,Pos(a,b)-Length(a));
    after := Copy(b,Pos(a,b)+Length(a),Length(b));
    Result := before + after;
    Result := RemoveAllAFromB(a,Result);  //recursive
  end;
end;

и в C я пишу это:

char *s1, *s2, *result; /* original strings and the result string */
int len1, len2; /* lengths of the strings */
for (i = 0; i < len1; i++) {
   for (j = 0; j < len2; j++) {
     if (s1[i] == s2[j]) {
       break;
     }
   }
   if (j == len2) {  /* s1[i] is not found in s2 */
     *result = s1[i]; 
     result++; /* assuming your result array is long enough */
   }
}

но сколько оптимизаций есть в версии C? Мы принимаем много решений о реализации, о которых я не думаю в версии Delphi. Как реализуется строка? В Дельфах я этого не вижу. В C я решил, что это будет указатель на массив целых чисел ASCII, которые мы называем символами. В C мы проверяем существование персонажа по одному за раз. В Delphi я использую Pos.

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


Я его еще не видел, так что скажу:С имеет тенденцию быть быстрее, потому что почти все остальное написано на C.

Java построен на C, Python построен на C (или Java, или .NET и т. д.), Perl is и т. д. ОС написана на C, виртуальные машины написаны на C, компиляторы написаны на C, интерпретаторы написаны на C. Некоторые вещи все еще написаны на языке ассемблера, который имеет тенденцию быть еще быстрее. Сейчас все больше и больше вещей написано чем-то другим, что само написано на С.

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

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

Как я могу иметь мой торт и съесть его тоже? Как я могу играть с абстракциями высокого уровня на моем любимом языке, а затем опуститься до мелкого песка C для скорость?

после нескольких лет исследований мой ответ-Python (на C). Возможно, вы захотите взглянуть. Кстати, вы также можете перейти к сборке с Python (с некоторой незначительной помощью из специальной библиотеки).

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

наслаждайтесь.


там много вопросов - в основном те, на которые я не квалифицирован, чтобы ответить. Но для этого последнего:

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

одним словом, абстракция.

C-это только один или 2 уровня абстракции от машинного языка. Java и языки .Net находятся как минимум на 3 уровнях абстракции от ассемблера. Я не уверен Python и Ruby.

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

Я здесь и там, но это основная суть.

обновление ------- есть несколько хороших комментариев по этому сообщению с более подробной информацией.


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

два языка, которые обычно компилируются в двоичные файлы, которые так же быстро, как C, являются стандартными ML (используя MLton компилятора) и Цель Caml. Если вы проверите игра ориентиры вы обнаружите, что для некоторых тестов, таких как двоичные деревья, версия OCaml быстрее, чем C. (Я не нашел записей MLton.) Но не воспринимайте перестрелку слишком серьезно; это, как говорится, игра, результаты часто отражают, сколько усилий люди вложили в настройку кода.


C не всегда быстрее.

C медленнее, чем, например, современный Fortran.

C часто медленнее, чем Java для некоторых вещей. (Особенно после того, как компилятор JIT попробовал ваш код)

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

предположение, что арифметика указателя действительно работает, вызывает медленное раздутая производительность на некоторых семействах CPU (особенно PIC!) Раньше он сосал большой на сегментированном x86.

в принципе, когда вы получаете векторную единицу или параллелизирующий компилятор, C воняет и современный Fortran работает быстрее.

C программист трюки, такие как thunking (изменение исполняемого файла на лету) причина CPU prefetch киоски.

вы получаете дрейф ?

и наш хороший друг, x86, выполняет набор инструкций, который в эти дни несет мало отношение к фактической архитектуре ЦП. Теневые регистры, оптимизаторы нагрузки-магазина, все в CPU. Таким образом, C близок к виртуальному металлу. Настоящий металл, разведка не позволит вам увидеть. (Исторически VLIW CPU были немного перебором, так что, возможно, это не так уж плохо.)

Если вы программируете на C на высокопроизводительном DSP (возможно, TI DSP ?), компилятор должен сделать некоторые хитрые вещи, чтобы развернуть C через несколько параллельных блоков выполнения. Так что в этом случае C не близок к металлу, но он близок к компилятору, который будет делать ВСЮ оптимизацию программы. Странный.

и, наконец, некоторые процессоры (www.ajile.com) запустите байт-коды Java в аппаратном обеспечении. C будет Пита для использования на этом процессоре.


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

ничего. Современные языки, такие как Java или .NET langs, больше ориентированы на производительность программиста, а не на производительность. Аппаратное обеспечение дешево сейчас. Также компиляции промежуточное представление дает много бонусов, таких как безопасность, переносимость и т. д. .NET CLR может использовать различное оборудование - например, вам не нужно вручную оптимизируйте / перекомпилируйте программу для использования набора инструкций SSE.


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

вот некоторые другие факторы, которые приходят на ум.

  • переменные не инициализируются автоматически
  • нет проверки границ массивов
  • непроверенная манипуляция указателем
  • нет переполнения целого числа проверка
  • статически-типизированные переменные
  • вызовы функций являются статическими (если вы не используете указатели функций)
  • у авторов компиляторов было много времени, чтобы улучшить оптимизирующий код. Кроме того, люди программируют на C с целью получения наилучшей производительности, поэтому существует давление для оптимизации кода.
  • части спецификации языка определены реализацией, поэтому компиляторы свободны делать вещи в самом оптимальном путь

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


Я думаю, вы забыли, что язык ассемблера также является языком:)

но серьезно, c-программы быстрее, только когда программист знает, что он делает. Вы можете легко написать программу на C, которая работает медленнее, чем программы, написанные на других языках, которые выполняют ту же работу.

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

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


C++ в среднем быстрее (так как изначально это был супер набор C). Однако для конкретных критериев часто существует другой язык, который быстрее.

https://benchmarksgame-team.pages.debian.net/benchmarksgame/

fannjuch-redux был самым быстрым в Scala

n-body и fasta были быстрее в Ada.

spectral-norm был самым быстрым в Фортране.

reverse-complement, mandelbrot и pidigits были самыми быстрыми в АТС.

regex-dna был самым быстрым в JavaScript.

chameneou-redux был самым быстрым Java 7.

thread-ring был самым быстрым в Хаскелле.

Остальные тесты были самыми быстрыми на C или c++.


Я не думаю, что кто-то упомянул тот факт, что в компиляторы C было вложено гораздо больше усилий, чем в любой другой компилятор, за исключением Java.

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

Я думаю, есть по крайней мере один язык кандидат, который с трудом можно было бы оптимизировать лучше, чем C, и поэтому мы могли бы видеть реализации, которые производят более быстрые двоичные файлы. Я думаю о digital mars D, потому что создатель позаботился о создании языка, который потенциально может быть лучше оптимизирован, чем C. могут быть другие языки, которые имеют такую возможность. Однако я не могу представить, что любой язык будет иметь компиляторы более чем на несколько процентов быстрее, чем лучшие компиляторы C. Мне бы хотелось ошибиться.

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

также важно (по крайней мере для меня), что худший код имеет тенденцию быть быстрым. Там многочисленные "доказательства" в интернете, что Java так же быстро или быстрее, чем C, но это основано на примерах выбора вишни. Я не большой поклонник C, но я знаю, что все, что я пишу на C, будет работать хорошо. С Java он будет" вероятно " работать в пределах 15% скорости, обычно в пределах 25%, но в некоторых случаях это может быть намного хуже. Любые случаи, когда это так же быстро или в пределах нескольких процентов, обычно связаны с большей частью времени, проводимого в коде библиотеки, который в любом случае сильно оптимизирован C.


по большей части каждая инструкция C соответствует очень нескольким инструкциям ассемблера. Вы по существу пишете машинный код более высокого уровня, поэтому вы контролируете почти все, что делает процессор. Многие другие скомпилированные языки, такие как C++, имеют много простых инструкций, которые могут превратиться в гораздо больше кода, чем вы думаете (виртуальные функции, конструкторы копирования и т. д..) И интерпретируемые языки, такие как Java или Ruby, имеют другой уровень инструкций, которые вы никогда не видеть-виртуальную машину или интерпретатор.


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

одна большая ослепительная дыра, о которой люди склонны забывать, - это когда программа должна блокировать какой-то IO, например, пользовательский ввод в любой программе GUI. В этих случаях не имеет значения, какой язык вы используете, поскольку вы ограничены скоростью, с которой данные могут поступать чем то, как быстро вы можете это обработать. В этом случае не имеет большого значения, используете ли вы C, Java, C# или даже Perl; вы просто не можете идти быстрее, чем данные могут войти.

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

Это также поднимает интересный момент о C и тем более в C++. Существует что-то вроде философии дизайна: "Если вам это не нужно, вы не платите за это."Проблема в том, что если вы делаете хочешь этого, в итоге платишь за это сполна. Например, реализация vtable в Java имеет тенденцию быть намного лучше, чем реализации C++, поэтому вызовы виртуальных функций намного быстрее. С другой стороны, у вас нет выбора, кроме как использовать виртуальные функции в Java, и они все еще чего-то стоят, но в программах, которые используют много виртуальных функций, снижается стоимость.


многие из этих ответов дают веские причины того, почему C является или не является более быстрым (в целом или в конкретных сценариях). Это бесспорно, что:

  • многие другие языки предоставляют автоматические функции, которые мы принимаем как должное. Например, проверка границ, проверка типа времени выполнения и автоматическое управление памятью не предоставляются бесплатно. Есть по крайней мере некоторые стоимость, связанная с этими функциями, о которых мы не можем думать-или даже реализовать-в то время как написание кода, использующего эти функции.
  • шаг от источника к машине часто не так прямо на других языках, как в C.
  • OTOH, сказать, что скомпилированный код C выполняется быстрее, чем другой код, написанный на других языках, - это обобщение, которое не всегда верно. Контрпримеры легко найти (или придумать).

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

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

в качестве примера рассмотрим простую программу Windows, в которой создается одно главное окно. Версия C будет заполнять a WNDCLASS[EX] структура, которая будет передана RegisterClass[Ex], тогда звоните CreateWindow[Ex] и введите цикл сообщений. Сильно упрощенный и сокращенный код ниже:

WNDCLASS wc;
MSG      msg;

wc.style         = 0;
wc.lpfnWndProc   = &WndProc;
wc.cbClsExtra    = 0;
wc.cbWndExtra    = 0;
wc.hInstance     = hInstance;
wc.hIcon         = NULL;
wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName  = NULL;
wc.lpszClassName = "MainWndCls";

RegisterClass(&wc);

CreateWindow("MainWndCls", "", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
             CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

while(GetMessage(&msg, NULL, 0, 0)){
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

эквивалентной программой на C# может быть только одна строка кода:

Application.Run(new Form());

эта одна строка кода предоставляет все функции, которые сделали почти 20 строк кода C, и добавляет некоторые вещи, которые мы пропустили, такие как проверка ошибок. Более богатая, более полная библиотека (по сравнению с теми, которые используются в типичном проекте C) сделала много работайте на нас, освобождая наше время для написания еще большего количества фрагментов кода, которые кажутся нам короткими, но включают в себя много шагов за кулисами.

но богатая библиотека, позволяющая легко и быстро раздувать код, на самом деле не моя точка зрения. Моя точка зрения более очевидна, когда вы начинаете изучать, что на самом деле происходит, когда наш маленький однострочный фактически выполняется. Для развлечения иногда,включить доступ к источнику .NET в Visual Studio 2008 или выше, и шаг в простой linef выше. Одно из веселья маленькие драгоценные камни, с которыми вы столкнетесь, - это комментарий в геттере для Control.CreateParams:

// In a typical control this is accessed ten times to create and show a control.
// It is a net memory savings, then, to maintain a copy on control.
// 
if (createParams == null) {
    createParams = new CreateParams(); 
} 

в десять раз. Информация примерно эквивалентна сумме того, что хранится в WNDCLASSEX структура и то, что передано CreateWindowEx извлекается из Control класса в десять раз до он хранится в WNDCLASSEX структура и передал RegisterClassEx и CreateWindowEx.

в целом, количество инструкций, выполненных для выполнения этой самой основной задачи на 2-3 порядка больше в C# , чем в C. частично это связано с использованием многофункциональной библиотеки, которая обязательно обобщается, по сравнению с нашим простым кодом C, который делает именно то, что нам нужно, и ничего больше. Но отчасти это связано с тем, что модульная, объектно-ориентированная природа .NET framework, поддается большому количеству повторений выполнения, чего часто избегает процедурный подход.

Я не пытаюсь выбрать C# или .NET framework. И я говоря, что модульность, обобщение, библиотечные / языковые функции, ООП и т. д. are плохое. Я использовал большую часть своей разработки на C, позже на C++ и в последнее время на C#. Аналогично, до C я использовал в основном сборку. И с каждым шагом" выше " мой язык идет, я пишу лучше, более ремонтопригодные, более надежные программы за меньшее время. Однако они, как правило, выполняются немного медленнее.


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

эти библиотеки были написаны в то время, когда вычислительная мощность и память были на первом месте. Их нужно было написать!--3-->очень эффективно работать на всех. Разработчики компиляторов C также долгое время работали во всевозможных умных оптимизация для разных процессоров. Зрелость и широкое принятие C дает значительное преимущество перед другими языками того же возраста. Это также дает преимущества в скорости с более новыми инструментами, которые не подчеркивают производительность как С пришлось.


отсутствие абстракции, чем быстрее. Если вы пишете оператор вывода, вы точно знаете, что происходит. Если вы пишете оператор вывода на java, он компилируется в файл класса, который затем запускается на виртуальной машине, представляя слой абстракции. Отсутствие объектно-ориентированных функций как части языка также увеличивает его скорость до меньшего количества генерируемого кода. Если вы используете C в качестве объектно-ориентированного языка, то вы делаете все кодирование для вещей таких как классы, inharitence и т. д. Это означает, что вместо того, чтобы сделать что-то обобщенное достаточно для всех с количеством кода и производительности penelty, что требует от вас только написать то, что вам нужно, чтобы получить работу.


удивительно видеть старый " C / C++ должны быть быстрее, чем Java, потому что Java интерпретируется " миф все еще жив и ногами. Есть статьи, относящиеся к нескольким годам, а также новые, что объяснить понятия и мерки почему это просто не всегда так.

текущие реализации виртуальных машин (и не только JVM, кстати) могут воспользоваться информацией, собранной во время программы выполнение для динамической настройки кода по мере его выполнения, используя различные методы:

  • рендеринг частых методов машинного кода,
  • встраивание небольших методов,
  • настройки замок

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


самый быстрый код будет тщательно ручной машинный код. Ассемблер будет почти так же хорош. Оба они очень низкого уровня, и для этого требуется много написания кода. C немного выше ассемблера. У вас все еще есть возможность управлять вещами на очень низком уровне в реальной машине, но достаточно абстракции, чтобы писать ее быстрее и проще, чем ассемблер. Другие языки, такие как C# и JAVA, еще более абстрактны. В то время как ассемблер и машинный код называются low языки уровня, C# и JAVA (и многие другие) называются языками высокого уровня. C иногда называют языком среднего уровня.


Я знаю, что многие люди говорили это долго, но:

C-это быстрее, потому что он делает меньше (для вас).


в старые добрые времена существовало только два типа языков: скомпилированный и интерпретированный.

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

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

возвращаясь к C, это простой язык, который можно скомпилировать в довольно оптимизированную сборку, а затем запустить непосредственно на целевой машине. В C, если вы увеличиваете целое число, более чем вероятно, что это только один шаг ассемблера в CPU, в Java, однако, это может оказаться намного больше, чем это (и может включать немного сборки мусора: -) C предлагает вам абстракцию, которая намного ближе к машине (ассемблер ближе всего), но вам в конечном итоге придется делать больше работы, чтобы заставить ее работать, и она не так защищена, проста в использовании или удобна для ошибок. Большинство других языков дают вам более высокую абстракцию и заботятся о большей части базовых деталей для вас, но в обмен на их расширенную функциональность они требуют больше ресурсов для запуска. По мере обобщения некоторых решений вам приходится обрабатывать более широкий диапазон вычислений, который часто требует больше ресурсов.

Павел.


Не принимайте чье-то слово за это, посмотрите на разборку как для C, так и для вашего языка выбора в любой критической части вашего кода. Я думаю, вы можете просто посмотреть в окне разборки во время выполнения в Visual Studio, чтобы увидеть разборку .Сеть. Должно быть возможно, если сложно для Java с помощью windbg, хотя если вы сделаете это с .Net, многие из проблем будут одинаковыми.

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

первый раз я сравнил код JITed с машинным кодом решены все вопросы, будь .Net код может сравнительно запустить C код. Дополнительный уровень абстракции и все проверки безопасности приходят со значительной стоимостью. Те же затраты, вероятно, применимы к Java, но не верьте мне на слово, попробуйте его на чем-то, где производительность критична. (Кто-нибудь знает достаточно о JITed Java, чтобы найти скомпилированную процедуру в памяти? Это, конечно, должно быть возможно)


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

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


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

причина, по которой Джефф и Джоэл говорят о том, что C является "настоящим программистом", заключается в том, что в C. Вы должны выделить свою собственную память, освободить эту память, сделать свою собственную проверку границ и т. д. Нет такой вещи, как new object(); нет сборки мусора, классов, OOP, Entity Framework, LINQ, свойств, атрибутов, полей или чего-либо подобного. Вы должны знать такие вещи, как арифметика указателя и как разыменовать указатель. И за это важно, знать и понимать, что такое указатель. Вы должны знать, что фрейм стека и указатель команд. Вы должны знать модель памяти архитектуры процессора, над которой вы работаете. Существует много неявного понимания архитектуры микрокомпьютера (обычно на микрокомпьютер, над которым вы работаете) при программировании на C, которого просто нет и нет необходимости при программировании на C# или Java. Вся эта информация была выгружена программисту компилятора (или виртуальной машины).


1) Как говорили другие, C делает для вас меньше. Нет инициализирующих переменных, нет проверки границ массива,нет управления памятью и т. д. Эти функции на других языках стоят памяти и циклов процессора, которые C не тратит.

2) Ответы, говорящие, что C менее абстрактен и, следовательно, быстрее, только наполовину правильны, я думаю. Технически говоря, если у вас есть" достаточно продвинутый компилятор " для языка X, то язык X может приблизиться или равняться скорости C. Разница с C это так очевидно (если вы взяли курс архитектуры) и непосредственно на ассемблер, что даже наивный компилятор может сделать достойную работу. Для чего-то вроде Python вам нужен очень продвинутый компилятор, чтобы предсказывать вероятные типы объектов и генерировать машинный код на лету-семантика C достаточно проста, что простой компилятор может сделать хорошо.


разница между автоматическим и ручным, языки более высокого уровня абстракции таким образом автоматизированы. C / C++ управляются и обрабатываются вручную, даже код проверки ошибок иногда является ручным трудом.

C и C++ также являются скомпилированными языками, что означает, что ни один из них не работает везде, эти языки должны быть точно настроены для оборудования, с которым вы работаете, таким образом, добавляя дополнительный слой gotcha. Хотя это немного ослабевает сейчас, когда компиляторы C / C++ становятся больше общего на всех платформах. Вы можете делать перекрестные компиляции между платформами. Это все еще не везде ситуация, ваш в основном инструктирующий компилятор a для компиляции против компилятора B тот же код другой архитектуры.

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

вот почему вы получаете сумасшедшие вещи, такие как (микро-архитектуры, драйверы, квантовая физика, игры AAA, операционные системы) есть вещи, для которых C и c++ просто хорошо подходят. Скорость и количество хруста являются главными областями.


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

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

более фундаментальным преимуществом C (и в аналогичной степени тесно связанного c++) является сильная зависимость от распределение памяти на основе стека, которая составляет быстрые для выделения, освобождения и доступа. В C (и C++) главная стек вызовов может использоваться для выделения примитивов, массивов и агрегатов (struct/class).

В то время как C предлагает возможность динамически выделять память произвольного размера и lifetime (используя так называемую "кучу"), по умолчанию этого избегается (вместо этого используется стек).

мучительно, иногда можно реплицировать стратегию выделения памяти C в средах выполнения других языков программирования. Это было продемонстрировано asm.js, что позволяет код, написанный на C или c++, быть переведенным в подмножество JavaScript и безопасно работать в среде веб-браузера-с почти родной скорость.


как несколько в стороне, другая область, где C и c++ затмевают большинство других языков для скорости, - это возможность плавной интеграции с собственными наборами команд машины. Заметным примером этого является (зависящая от компилятора и платформы) доступность SIMD внутреннеприсущие которые поддерживают конструкцию изготовленных на заказ алгоритмов которые используют преимущество теперь почти вездесущего оборудования параллельной обработки -- пока все еще использующ распределение данных абстракции, предоставляемые языком (распределение регистров нижнего уровня управляется компилятором).


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

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

возникает вопрос: почему? Что в C++ и Fortran делает их быстрыми и почему они превосходят другие популярные языки, такие как Java или Python?

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

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

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

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

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

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

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

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

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

Если вы хотите узнать больше, пожалуйста, проверьте источник


даже разница между C и C++ может быть большой.

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

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

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

C также выполняет намного меньше проверки ошибок, чем другие языки, предполагая, что программист знает, что они делают. Итак, тогда как в PHP, если вы объявляете строку $myStr = getInput(); и перейти к ссылке $myStr[20], но вход был длиной всего 10 символов, PHP поймает это и безопасно вернет вам пустую строку. C предполагает, что вы либо выделили достаточно памяти для хранения данных после конца строки, либо знаете, какая информация приходит после строки и вместо этого пытаюсь сослаться на это. Эти небольшие факторы оказывают огромное влияние на совокупные накладные расходы.


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

оптимизация компилятора переоценена, как и почти все представления о скорости языка.

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