Насколько я понимаю, C / C ++ создает собственный код для работы на конкретной архитектуре компьютера. И наоборот, такие языки, как Java и C #, работают поверх виртуальной машины, которая абстрагируется от собственной архитектуры. Логически казалось бы невозможным для Java или C # соответствовать скорости C ++ из-за этого промежуточного шага, однако мне сказали, что последние компиляторы («горячая точка») могут достичь этой скорости или даже превзойти ее.
Возможно, это скорее вопрос компилятора, чем вопрос языка, но может ли кто-нибудь объяснить на простом английском, как может один из этих языков виртуальных машин работать лучше, чем родной язык?
Ответы:
Как правило, C # и Java могут быть такими же быстрыми или быстрее, потому что JIT-компилятор - компилятор, который компилирует ваш IL при первом запуске - может выполнять оптимизацию, которую скомпилированная программа C ++ не может сделать, потому что она может запрашивать машину. Он может определить, является ли машина Intel или AMD; Pentium 4, Core Solo или Core Duo; или если поддерживает SSE4 и т. д.
Программа на C ++ должна быть скомпилирована заранее, как правило, со смешанными оптимизациями, чтобы она работала достаточно хорошо на всех машинах, но не оптимизировалась настолько, насколько это могло бы быть для одной конфигурации (например, процессора, набора команд, другого оборудования).
Кроме того, некоторые языковые функции позволяют компилятору C # и Java делать предположения о вашем коде, что позволяет ему оптимизировать определенные части, которые просто небезопасны для компилятора C / C ++. Когда у вас есть доступ к указателям, существует множество оптимизаций, которые просто небезопасны.
Кроме того, Java и C # могут выполнять распределение кучи более эффективно, чем C ++, потому что уровень абстракции между сборщиком мусора и вашим кодом позволяет ему выполнять все сжатие кучи сразу (довольно дорогостоящая операция).
Теперь я не могу говорить от имени Java по этому следующему пункту, но я знаю, что, например, C # фактически удалит методы и вызовы методов, когда узнает, что тело метода пусто. И он будет использовать такую логику во всем вашем коде.
Итак, как видите, есть множество причин, по которым определенные реализации C # или Java будут быстрее.
Теперь, когда все сказано, в C ++ можно сделать определенные оптимизации, которые сведут на нет все, что вы могли бы сделать с C #, особенно в области графики и в любое время, когда вы находитесь рядом с оборудованием. Указатели здесь творят чудеса.
Так что, в зависимости от того, что вы пишете, я бы выбрал то или иное. Но если вы пишете что-то, что не зависит от оборудования (драйвер, видеоигра и т. Д.), Я бы не стал беспокоиться о производительности C # (опять же, не могу говорить о Java). Это будет нормально.
Со стороны Java, @Swati указывает на хорошую статью:
https://www.ibm.com/developerworks/library/j-jtp09275
источник
JIT против статического компилятора
Как уже было сказано в предыдущих сообщениях, JIT может компилировать IL / байт-код в собственный код во время выполнения. Стоимость этого была названа, но не до конца:
У JIT есть одна серьезная проблема: он не может скомпилировать все: JIT-компиляция требует времени, поэтому JIT будет компилировать только некоторые части кода, тогда как статический компилятор создаст полный собственный двоичный код: для некоторых программ статический компилятор просто легко превзойдет JIT.
Конечно, C # (или Java, или VB) обычно быстрее создает жизнеспособное и надежное решение, чем C ++ (хотя бы потому, что C ++ имеет сложную семантику, а стандартная библиотека C ++, хотя и интересна и мощна, но довольно плохая по сравнению с полной версией. объем стандартной библиотеки из .NET или Java), поэтому обычно разница между C ++ и .NET или Java JIT не будет видна большинству пользователей, а для тех двоичных файлов, которые имеют решающее значение, вы все равно можете вызвать обработку C ++ из C # или Java (даже если такие нативные вызовы могут быть довольно дорогостоящими сами по себе) ...
C ++ метапрограммирование
Обратите внимание, что обычно вы сравниваете код времени выполнения C ++ с его эквивалентом на C # или Java. Но у C ++ есть одна особенность, которая может превзойти Java / C # из коробки, а именно метапрограммирование шаблонов: обработка кода будет выполняться во время компиляции (что значительно увеличивает время компиляции), что приводит к нулевому (или почти нулевому) времени выполнения.
Я пока еще не вижу реального влияния на это (я играл только с концепциями, но к тому времени разница составляла секунды выполнения для JIT и ноль для C ++), но это стоит упомянуть, наряду с тем, что метапрограммирование шаблона не является тривиальна ......
Собственное использование памяти C ++
C ++ использует память, отличную от Java / C #, и, следовательно, имеет другие преимущества / недостатки.
Независимо от JIT-оптимизации, ничто не пойдет так быстро, как прямой указатель доступа к памяти (давайте на минутку проигнорируем кеши процессора и т. Д.). Таким образом, если у вас есть непрерывные данные в памяти, доступ к ним через указатели C ++ (то есть указатели C ... Давайте отдадим должное Caesar) будет происходить в разы быстрее, чем в Java / C #. А в C ++ есть RAII, что значительно упрощает обработку, чем в C # или даже в Java. С ++ не нужно
using
ограничивать существование своих объектов. А в C ++ нетfinally
пункта. Это не ошибка.:-)
И, несмотря на примитивные структуры C #, объекты C ++ "в стеке" ничего не стоят при распределении и уничтожении, и им не потребуется сборщик мусора для работы в независимом потоке для очистки.
Что касается фрагментации памяти, распределители памяти в 2008 году - это не старые распределители памяти 1980 года, которые обычно сравнивают с GC: распределение C ++ не может быть перемещено в память, правда, но тогда, как в файловой системе Linux: кому нужен жесткий диск дефрагментация, когда фрагментации не происходит? Использование правильного распределителя для правильной задачи должно быть частью набора инструментов разработчика C ++. Теперь написать распределители памяти непросто, и тогда у большинства из нас есть дела поважнее, и для большинства случаев использования RAII или GC более чем достаточно.
Теперь модель памяти несколько усложняется с появлением многоядерных и многопоточных технологий. В этой области, я полагаю, .NET имеет преимущество, а Java, как мне сказали, занимает верхнюю позицию. Некоторому хакеру, работающему на «голом железе», легко похвалить его код «около машины». Но сейчас гораздо труднее произвести лучшую сборку вручную, чем позволить компилятору выполнять свою работу. Для C ++ компилятор обычно становился лучше, чем хакерский за последние десять лет. Для C # и Java это еще проще.
Тем не менее, новый стандарт C ++ 0x наложит простую модель памяти на компиляторы C ++, которая стандартизирует (и, таким образом, упростит) эффективный код многопроцессорной / параллельной / многопоточной обработки в C ++ и сделает оптимизацию более простой и безопасной для компиляторов. Но потом, через пару лет мы увидим, будут ли выполнены его обещания.
C ++ / CLI против C # / VB.NET
Примечание. В этом разделе я говорю о C ++ / CLI, то есть о C ++, размещенном в .NET, а не о собственном C ++.
На прошлой неделе я прошел тренинг по оптимизации .NET и обнаружил, что статический компилятор в любом случае очень важен. Не менее важно, чем JIT.
Тот же самый код, скомпилированный на C ++ / CLI (или его предке, Managed C ++), может быть в разы быстрее, чем тот же код, созданный на C # (или VB.NET, компилятор которого создает тот же IL, что и C #).
Потому что статический компилятор C ++ был намного лучше для создания уже оптимизированного кода, чем C #.
Например, встраивание функций в .NET ограничено функциями, длина байт-кода которых меньше или равна 32 байтам. Итак, некоторый код на C # создаст 40-байтовый метод доступа, который никогда не будет встроен JIT. Тот же код в C ++ / CLI создаст 20-байтовый метод доступа, который будет встроен JIT.
Другой пример - временные переменные, которые просто компилируются компилятором C ++, но при этом упоминаются в IL, созданном компилятором C #. Оптимизация статической компиляции C ++ приведет к меньшему количеству кода, таким образом, снова разрешит более агрессивную JIT-оптимизацию.
Причиной этого было предположение, что компилятор C ++ / CLI извлек выгоду из обширных методов оптимизации собственного компилятора C ++.
Вывод
Я люблю C ++.
Но, насколько я понимаю, C # или Java в целом лучше. Не потому, что они быстрее, чем C ++, а потому, что, когда вы складываете их качества, они оказываются более продуктивными, нуждаются в меньшем обучении и имеют более полные стандартные библиотеки, чем C ++. Да и у большинства программ разница в скорости (так или иначе) будет незначительной ...
Изменить (2011-06-06)
Мой опыт работы с C # /. NET
Сейчас у меня 5 месяцев почти эксклюзивного профессионального программирования на C # (что дополняет мое резюме, уже полное C ++ и Java, а также немного C ++ / CLI).
Я играл с WinForms (кхм ...) и WCF (круто!) И WPF (круто !!!! Как через XAML, так и через необработанный C #. WPF настолько прост, я считаю, что Swing просто не может сравниться с ним) и C # 4.0.
Вывод таков: хотя легче / быстрее создать код, работающий на C # / Java, чем на C ++, гораздо сложнее создать надежный, безопасный и надежный код на C # (и даже сложнее на Java), чем на C ++. Причин предостаточно, но их можно резюмировать следующим образом:
using
не такой простой и мощный, потому что писать правильные реализации Dispose сложно )readonly
и Javafinal
нигде не так полезны, как C ++const
( вы не можете раскрыть сложные данные только для чтения (например, дерево узлов) в C # без огромной работы, хотя это встроенная функция C ++. Неизменяемые данные - интересное решение , но не все можно сделать неизменяемым, поэтому этого явно недостаточно ).Итак, C # остается приятным языком, пока вы хотите что-то, что работает, но разочаровывающим языком в тот момент, когда вам нужно что-то, что всегда и безопасно работает.
Java вызывает еще большее разочарование, поскольку имеет те же проблемы, что и C #, и даже больше: из-за отсутствия эквивалента
using
ключевого слова C # мой очень опытный коллега потратил слишком много времени, чтобы убедиться, что его ресурсы правильно освобождены, тогда как эквивалент в C ++ имел бы было легко (с использованием деструкторов и умных указателей).Поэтому я полагаю, что прирост производительности C # / Java заметен для большей части кода ... до того дня, когда вам понадобится сделать код как можно более совершенным. В тот день ты познаешь боль. (вы не поверите, что спрашивают наши серверы и приложения с графическим интерфейсом ...).
О серверной Java и C ++
Я поддерживал связь с серверными командами (я проработал с ними 2 года, прежде чем вернуться в команду GUI) на другой стороне здания, и я узнал кое-что интересное.
В последние годы была тенденция к тому, чтобы серверные приложения Java были предназначены для замены старых серверных приложений C ++, поскольку Java имеет множество фреймворков / инструментов, проста в обслуживании, развертывании и т. Д. И т. Д.
... До тех пор, пока проблема низкой задержки не подняла свою уродливую голову в последние месяцы. Затем серверные приложения Java, вне зависимости от попыток оптимизации, предпринятых нашей опытной командой разработчиков Java, просто проиграли гонку старому, не совсем оптимизированному серверу C ++.
В настоящее время принято решение оставить серверы Java для общего использования там, где производительность, хотя и важна, не зависит от цели с низкой задержкой, и агрессивно оптимизировать и без того более быстрые серверные приложения C ++ для нужд с низкой и сверхнизкой задержкой.
Вывод
Нет ничего проще, чем ожидалось.
Java и даже C # - отличные языки с обширными стандартными библиотеками и фреймворками, где вы можете быстро кодировать и очень скоро получить результат.
Но когда вам нужна чистая мощность, мощная и систематическая оптимизация, сильная поддержка компилятора, мощные языковые функции и абсолютная безопасность, Java и C # затрудняют достижение последнего недостающего, но критического процента качества, вам нужно оставаться выше конкурентов.
Как будто вам нужно меньше времени и менее опытных разработчиков на C # / Java, чем на C ++, чтобы создать код среднего качества, но, с другой стороны, в тот момент, когда вам нужно было отличное или идеальное качество кода, стало внезапно легче и быстрее получить результаты. прямо в C ++.
Конечно, это мое собственное восприятие, возможно, ограниченное нашими конкретными потребностями.
Но, тем не менее, это то, что происходит сегодня, как в командах GUI, так и в командах на стороне сервера.
Конечно, я обновлю этот пост, если произойдет что-то новое.
Изменить (2011-06-22)
Источники:
Изменить (2011-09-20)
Источники:
источник
Всякий раз, когда я говорю об управляемой и неуправляемой производительности, мне нравится указывать на серию статей, в которых Рико (и Раймонд) сравнивали версии китайско-английского словаря на C ++ и C #. Этот поиск в Google позволит вам прочитать сами, но мне нравится резюме Рико.
Для меня суть в том, что неуправляемой версии потребовалось 6 ревизий, чтобы превзойти управляемую версию, которая была простым портом исходного неуправляемого кода. Если вам нужен каждый последний бит производительности (и у вас есть время и опыт, чтобы получить его), вам придется отказаться от управления, но для меня я воспользуюсь преимуществом на порядок, которое у меня есть в первых версиях над 33 % Я получаю, если попробую 6 раз.
источник
Компиляция для конкретных оптимизаций ЦП обычно переоценивается. Просто возьмите программу на C ++, скомпилируйте с оптимизацией для Pentium PRO и запустите на Pentium 4. Затем перекомпилируйте с optimize для Pentium 4. Я провел долгие дни, делая это с несколькими программами. Общие результаты ?? Обычно производительность увеличивается менее чем на 2-3%. Таким образом, теоретических преимуществ JIT практически нет. Большинство различий в производительности можно наблюдать только при использовании функций обработки скалярных данных, что в конечном итоге потребует точной настройки вручную для достижения максимальной производительности. Оптимизация такого рода медленная и дорогостоящая, что делает ее иногда непригодной для JIT.
В реальном мире и реальных приложениях C ++ по-прежнему обычно быстрее, чем java, в основном из-за меньшего объема памяти, что приводит к лучшей производительности кеша.
Но чтобы использовать все возможности C ++, разработчик должен много работать. Вы можете добиться превосходных результатов, но для этого нужно использовать свой мозг. C ++ - это язык, который решил предоставить вам больше инструментов по цене, которую вы должны изучить, чтобы иметь возможность хорошо использовать язык.
источник
JIT (Just In Time Compiling) может быть невероятно быстрым, потому что он оптимизируется для целевой платформы.
Это означает, что он может использовать любую уловку компилятора, которую поддерживает ваш ЦП, независимо от того, на каком ЦП разработчик написал код.
Основная концепция .NET JIT работает следующим образом (сильно упрощенная):
Первый вызов метода:
Вызов метода второй раз:
Как видите, во второй раз это практически тот же процесс, что и в C ++, за исключением оптимизации в реальном времени.
Тем не менее, есть и другие накладные расходы, замедляющие управляемый язык, но JIT очень помогает.
источник
Мне нравится орион адриан ответ , но есть еще один аспект.
Тот же вопрос был задан несколько десятилетий назад относительно языка ассемблера и «человеческих» языков, таких как FORTRAN. И часть ответа аналогична.
Да, программа на C ++ способна быть быстрее, чем C #, по любому заданному (нетривиальному?) Алгоритму, но программа на C # часто будет так же быстро или быстрее, чем «наивная» реализация на C ++ и оптимизированная версия на C ++. на разработку уйдет больше времени, и он все равно может превзойти версию C # с очень небольшим отрывом. Так действительно ли оно того стоит?
Вам придется отвечать на этот вопрос один за другим.
Тем не менее, я давний поклонник C ++ и считаю его невероятно выразительным и мощным языком, который иногда недооценивают. Но во многих «реальных» проблемах (лично для меня это означает «те, за решение которых мне платят») C # выполнит свою работу быстрее и безопаснее.
Самый большой штраф, который вы платите? Многие программы .NET и Java занимают много памяти. Я видел, как приложения .NET и Java занимают «сотни» мегабайт памяти, в то время как программы на C ++ аналогичной сложности едва занимают «десятки» мегабайт.
источник
Я не уверен, как часто вы обнаружите, что код Java будет работать быстрее, чем C ++, даже с Hotspot, но я попытаюсь объяснить, как это могло произойти.
Считайте скомпилированный код Java интерпретируемым машинным языком для JVM. Когда процессор Hotspot замечает, что определенные части скомпилированного кода будут использоваться много раз, он выполняет оптимизацию машинного кода. Поскольку ручная настройка Assembly почти всегда быстрее, чем код, скомпилированный на C ++, можно предположить, что программно настроенный машинный код тоже не будет плохим.
Итак, для очень повторяющегося кода я мог видеть, где JVM Hotspot сможет запускать Java быстрее, чем C ++ ... до тех пор, пока не вступит в игру сборка мусора. :)
источник
Since hand-tuning Assembly is almost always faster than C++ compiled code
? Что вы имеете в виду под "настраиваемой вручную сборкой" и "кодом, скомпилированным на C ++"?Как правило, алгоритм вашей программы будет намного важнее для скорости вашего приложения, чем язык. . Вы можете реализовать плохой алгоритм на любом языке, включая C ++. Имея это в виду, вы, как правило, сможете писать код, который запускается быстрее, на языке, который поможет вам реализовать более эффективный алгоритм.
Языки более высокого уровня преуспевают в этом, обеспечивая более легкий доступ ко многим эффективным предварительно созданным структурам данных и поощряя методы, которые помогут вам избежать неэффективного кода. Конечно, иногда они также могут упростить написание кучи действительно медленного кода, так что вам все равно нужно знать свою платформу.
Кроме того, C ++ догоняет «новые» (обратите внимание на кавычки) функции, такие как контейнеры STL, автоматические указатели и т. Д. - см., Например, библиотеку boost. И иногда вы можете обнаружить, что самый быстрый способ выполнить некоторую задачу требует такой техники, как арифметика указателей, которая запрещена в языках более высокого уровня, хотя обычно они позволяют вам обращаться к библиотеке, написанной на языке, который может реализовать ее по желанию. ,
Главное - знать, какой язык вы используете, связанный с ним API, что он может делать и каковы его ограничения.
источник
Я тоже не знаю ... мои программы на Java всегда медленные. :-) Я никогда особо не замечал, чтобы программы на C # были особенно медленными.
источник
Вот еще один интересный тест, который вы можете попробовать на собственном компьютере.
Он сравнивает ASM, VC ++, C #, Silverlight, Java-апплет, Javascript, Flash (AS3).
Демонстрация скорости плагина Roozz
Обратите внимание, что скорость javascript сильно зависит от того, какой браузер его запускает. То же самое верно для Flash и Silverlight, потому что эти плагины работают в том же процессе, что и хост-браузер. Но плагин Roozz запускает стандартные файлы .exe, которые запускаются в собственном процессе, поэтому браузер хоста не влияет на скорость.
источник
Вы должны определить «работать лучше, чем ..». Я знаю, вы спрашивали о скорости, но это еще не все.
И так далее, предвзято, да;)
Используя C # и Java, вы платите цену за то, что получаете (более быстрое кодирование, автоматическое управление памятью, большая библиотека и т. Д.). Но по мелочам торговаться особо некуда: бери весь пакет или ничего.
Даже если эти языки могут оптимизировать некоторый код для выполнения быстрее, чем скомпилированный код, весь подход (IMHO) неэффективен. Представьте себе, что вы каждый день проезжаете 5 миль до рабочего места на грузовике! Это удобно, приятно, вы в безопасности (крайняя зона деформации), а после того, как вы нажмете на газ в течение некоторого времени, он будет даже таким же быстрым, как стандартный автомобиль! Почему нам всем не ехать на работу на грузовике? ;)
В C ++ вы получаете то, за что платите, не больше и не меньше.
Цитата Бьярна Страуструпа: «C ++ - мой любимый язык со сборкой мусора, потому что он генерирует так мало мусора» текст ссылки
источник
times
на оболочке. Так что он проверяет всю программу, а не только один аспект. Тогда похожи ли результаты?Исполняемый код, созданный компилятором Java или C #, не интерпретируется - он компилируется в собственный код «точно в срок» (JIT). Итак, первый раз, когда код в программе Java / C # встречается во время выполнения, возникают некоторые накладные расходы, так как «компилятор времени выполнения» (он же JIT-компилятор) превращает байтовый код (Java) или код IL (C #) в машинные инструкции машинного кода. Однако в следующий раз, когда этот код будет встречен во время работы приложения, собственный код будет выполнен немедленно. Это объясняет, почему некоторые программы Java / C # сначала кажутся медленными, но затем работают лучше, чем дольше они работают. Хорошим примером является веб-сайт ASP.Net. Самый первый доступ к веб-сайту может быть немного медленнее, так как код C # компилируется в собственный код JIT-компилятором.
источник
Вот несколько хороших ответов на заданный вами вопрос. Я хотел бы сделать шаг назад и взглянуть на картину в целом.
Имейте в виду, что восприятие вашим пользователем скорости написанного вами программного обеспечения зависит от многих других факторов, помимо того, насколько хорошо оптимизирует кодогенератор. Вот некоторые примеры:
Ручное управление памятью трудно сделать правильно (без утечек), а еще сложнее сделать эффективно (освободите память вскоре после того, как вы закончите с ней). Использование GC, как правило, с большей вероятностью приведет к созданию программы, которая хорошо управляет памятью. Готовы ли вы очень усердно работать и отложить выпуск своего программного обеспечения, пытаясь превзойти сборщик мусора?
Мой C # легче читать и понимать, чем мой C ++. У меня также есть другие способы убедить себя, что мой код C # работает правильно. Это означает, что я могу оптимизировать свои алгоритмы с меньшим риском появления ошибок (а пользователям не нравится программное обеспечение, которое дает сбой, даже если оно делает это быстро!)
Я могу создавать свои программы на C # быстрее, чем на C ++. Это освобождает время для работы над производительностью и по-прежнему доставляет мое программное обеспечение вовремя.
Легче написать хороший пользовательский интерфейс на C #, чем на C ++, поэтому я с большей вероятностью смогу отодвинуть работу в фоновый режим, пока пользовательский интерфейс остается отзывчивым, или обеспечить прогресс или импульсный интерфейс, когда программе придется на некоторое время заблокироваться. Это не делает ничего быстрее, но делает пользователей более счастливыми в ожидании.
Все, что я сказал о C #, вероятно, верно и для Java, у меня просто нет опыта, чтобы сказать наверняка.
источник
Если вы программист на Java / C # и изучаете C ++, у вас возникнет соблазн продолжать думать в терминах Java / C # и дословно переводить синтаксис C ++. В этом случае вы получаете только упомянутые ранее преимущества нативного кода по сравнению с интерпретируемым / JIT. Чтобы получить наибольший прирост производительности в C ++ по сравнению с Java / C #, вам нужно научиться думать на C ++ и разрабатывать код специально для использования сильных сторон C ++.
Перефразируя Эдсгера Дейкстру : [ваш родной язык] калечит разум безвозвратно.
Перефразируя Джеффа Этвуда : вы можете писать [ваш первый язык] на любом новом языке.
источник
Одна из наиболее значительных JIT-оптимизаций - это встраивание методов. Java может даже встроить виртуальные методы, если это может гарантировать корректность выполнения. Этот вид оптимизации обычно не может быть выполнен стандартными статическими компиляторами, потому что он требует анализа всей программы, что сложно из-за отдельной компиляции (напротив, JIT имеет всю доступную программу). Встраивание методов улучшает другие оптимизации, предоставляя для оптимизации большие блоки кода.
Стандартное выделение памяти в Java / C # также происходит быстрее, а освобождение памяти (GC) не намного медленнее, но менее детерминировано.
источник
free
иdelete
также не являются детерминированными, и GC можно сделать детерминированным, не выделяя.Языки виртуальных машин вряд ли превзойдут по производительности скомпилированные языки, но они могут подойти настолько близко, что это не имеет значения, по (по крайней мере) следующим причинам (здесь я говорю от имени Java, поскольку я никогда не работал с C #).
1 / Среда выполнения Java обычно способна обнаруживать части кода, которые часто запускаются, и выполнять JIT-компиляцию этих разделов, чтобы в будущем они выполнялись с полной скоростью компиляции.
2 / Обширные части библиотек Java скомпилированы так, что, когда вы вызываете библиотечную функцию, вы выполняете скомпилированный код, а не интерпретируете. Вы можете увидеть код (на C), загрузив OpenJDK.
3 / Если вы не выполняете массовые вычисления, большую часть времени ваша программа ждет ввода от очень медленного (условно говоря) человека.
4 / Поскольку большая часть проверки байт-кода Java выполняется во время загрузки класса, обычные накладные расходы на проверки времени выполнения значительно сокращаются.
5 / В худшем случае требовательный к производительности код можно извлечь в скомпилированный модуль и вызвать из Java (см. JNI), чтобы он работал на полной скорости.
Таким образом, байт-код Java никогда не превзойдет собственный машинный язык, но есть способы смягчить это. Большим преимуществом Java (как мне кажется) является ОГРОМНАЯ стандартная библиотека и кроссплатформенность.
источник
Орион Адриан , позвольте мне перевернуть ваш пост, чтобы увидеть, насколько ваши замечания необоснованны, потому что о C ++ можно много сказать. И сообщение о том, что компилятор Java / C # оптимизирует пустые функции, действительно заставляет вас звучать так, как будто вы не мой эксперт по оптимизации, потому что а) почему настоящая программа должна содержать пустые функции, за исключением действительно плохого устаревшего кода, б) это действительно не черная и передовая оптимизация.
Помимо этой фразы, вы открыто говорили об указателях, но разве объекты в Java и C # в основном не работают как указатели C ++? Могут ли они не перекрываться? Разве они не могут быть нулевыми? C (и большинство реализаций C ++) имеет ключевое слово restrict, оба имеют типы значений, C ++ имеет ссылку на значение с ненулевой гарантией. Что предлагают Java и C #?
>>>>>>>>>>
Как правило, C и C ++ могут быть такими же быстрыми или более быстрыми, потому что компилятор AOT - компилятор, который раз и навсегда компилирует ваш код перед развертыванием на вашем многоядерном сервере сборки с большой памятью, - может выполнять оптимизацию, которую скомпилированная программа C # не может, потому что у него на это куча времени. Компилятор может определить, является ли машина Intel или AMD; Pentium 4, Core Solo или Core Duo; или если поддерживает SSE4 и т. д., и если ваш компилятор не поддерживает диспетчеризацию во время выполнения, вы можете решить эту проблему самостоятельно, развернув несколько специализированных двоичных файлов.
Программа AC # обычно компилируется после ее запуска, так что она неплохо работает на всех машинах, но не оптимизирована так сильно, как могла бы быть для одной конфигурации (например, процессора, набора команд, другого оборудования), и на нее нужно потратить некоторое время первый. Такие функции, как деление цикла, инверсия цикла, автоматическая векторизация, оптимизация всей программы, расширение шаблона, IPO и многие другие, очень трудно решить полностью и полностью таким образом, чтобы не раздражать конечного пользователя.
Кроме того, некоторые языковые функции позволяют компилятору C ++ или C делать предположения о вашем коде, что позволяет ему оптимизировать определенные части, которые просто небезопасны для компилятора Java / C #. Когда у вас нет доступа к полному идентификатору типа универсальных шаблонов или гарантированному потоку программы, существует множество оптимизаций, которые просто небезопасны.
Кроме того, C ++ и C выполняют множество распределений стека одновременно с увеличением только одного регистра, что, безусловно, более эффективно, чем выделения Javas и C #, в отношении уровня абстракции между сборщиком мусора и вашим кодом.
Теперь я не могу говорить о Java по этому следующему пункту, но я знаю, что компиляторы C ++, например, фактически удаляют методы и вызовы методов, когда он знает, что тело метода пусто, он устраняет общие подвыражения, он может попытаться повторить попытку чтобы найти оптимальное использование регистров, он не требует проверки границ, он будет автовекторизовать циклы и внутренние циклы и будет инвертировать внутренний во внешний, он перемещает условные выражения из циклов, он разбивает и не разделяет циклы. Он расширит std :: vector в собственные массивы с нулевыми накладными расходами, как если бы вы делали способ C. Он будет выполнять межпроцедурные оптимизации. Он будет создавать возвращаемые значения непосредственно на сайте вызывающего абонента. Он будет складывать и распространять выражения. Он будет переупорядочивать данные в удобном для кеша виде. Он будет выполнять скачкообразную заправку. Он позволяет писать трассировщики лучей во время компиляции с нулевыми издержками времени выполнения. Это сделает очень дорогостоящие оптимизации на основе графов. Это приведет к снижению прочности, если он заменит определенные коды синтаксически совершенно неравным, но семантически эквивалентным кодом (старый «xor foo, foo» - это всего лишь простейшая, хотя и устаревшая оптимизация такого рода). Если вы любезно спросите, вы можете опустить стандарты IEEE с плавающей запятой и включить еще больше оптимизаций, таких как изменение порядка операндов с плавающей запятой. После того, как он обработал и уничтожил ваш код, он может повторить весь процесс, потому что часто определенные оптимизации закладывают основу для еще более надежных оптимизаций. Он также может просто повторить попытку с перемешанными параметрами и посмотреть, как другой вариант оценивается во внутреннем рейтинге. И он будет использовать такую логику во всем вашем коде. если он заменяет определенные коды синтаксически совершенно неравным, но семантически эквивалентным кодом (старый «xor foo, foo» - это всего лишь простейшая, хотя и устаревшая оптимизация такого рода). Если вы любезно спросите, вы можете опустить стандарты IEEE с плавающей запятой и включить еще больше оптимизаций, таких как изменение порядка операндов с плавающей запятой. После того, как он обработал и уничтожил ваш код, он может повторить весь процесс, потому что часто определенные оптимизации закладывают основу для еще более надежных оптимизаций. Он также может просто повторить попытку с перемешанными параметрами и посмотреть, как другой вариант оценивается во внутреннем рейтинге. И он будет использовать такую логику во всем вашем коде. если он заменяет определенные коды синтаксически совершенно неравным, но семантически эквивалентным кодом (старый «xor foo, foo» - это всего лишь простейшая, хотя и устаревшая оптимизация такого рода). Если вы любезно спросите, вы можете опустить стандарты IEEE с плавающей запятой и включить еще больше оптимизаций, таких как изменение порядка операндов с плавающей запятой. После того, как он обработал и уничтожил ваш код, он может повторить весь процесс, потому что часто определенные оптимизации закладывают основу для еще более надежных оптимизаций. Он также может просто повторить попытку с перемешанными параметрами и посмотреть, как другой вариант оценивается во внутреннем рейтинге. И он будет использовать такую логику во всем вашем коде. Если вы любезно спросите, вы можете опустить стандарты IEEE с плавающей запятой и включить еще больше оптимизаций, таких как изменение порядка операндов с плавающей запятой. После того, как он обработал и уничтожил ваш код, он может повторить весь процесс, потому что часто определенные оптимизации закладывают основу для еще более надежных оптимизаций. Он также может просто повторить попытку с перемешанными параметрами и посмотреть, как другой вариант оценивается во внутреннем рейтинге. И он будет использовать такую логику во всем вашем коде. Если вы любезно спросите, вы можете опустить стандарты IEEE с плавающей запятой и включить еще больше оптимизаций, таких как изменение порядка операндов с плавающей запятой. После того, как он обработал и уничтожил ваш код, он может повторить весь процесс, потому что часто определенные оптимизации закладывают основу для еще более надежных оптимизаций. Он также может просто повторить попытку с перемешанными параметрами и посмотреть, как другой вариант оценивается во внутреннем рейтинге. И он будет использовать такую логику во всем вашем коде. Он также может просто повторить попытку с перемешанными параметрами и посмотреть, как другой вариант оценивается во внутреннем рейтинге. И он будет использовать такую логику во всем вашем коде. Он также может просто повторить попытку с перемешанными параметрами и посмотреть, как другой вариант оценивается во внутреннем рейтинге. И он будет использовать такую логику во всем вашем коде.
Итак, как видите, есть множество причин, по которым определенные реализации C ++ или C будут быстрее.
Все это говорит о том, что в C ++ можно сделать множество оптимизаций, которые сведут на нет все, что вы могли бы сделать с C #, особенно в области обработки чисел, в реальном времени и в области, близкой к металлу, но не только здесь. Вам даже не нужно прикасаться к указателю, чтобы пройти долгий путь.
Так что, в зависимости от того, что вы пишете, я бы выбрал то или иное. Но если вы пишете что-то, что не зависит от оборудования (драйвер, видеоигра и т. Д.), Я бы не стал беспокоиться о производительности C # (опять же, не могу говорить о Java). Это будет нормально.
<<<<<<<<<<
Как правило, некоторые обобщенные аргументы могут звучать круто в конкретных сообщениях, но в целом не кажутся убедительными.
В любом случае, чтобы помириться: AOT - это здорово, как и JIT . Единственно правильный ответ может быть: это зависит от обстоятельств. И настоящие умные люди знают, что вы в любом случае можете использовать лучшее из обоих миров.
источник
Это может произойти только в том случае, если интерпретатор Java создает машинный код, который на самом деле лучше оптимизирован, чем машинный код, который ваш компилятор генерирует для кода C ++, который вы пишете, до такой степени, что код C ++ медленнее, чем Java, и стоимость интерпретации.
Однако шансы на то, что это действительно произойдет, довольно низки - если, возможно, у Java нет очень хорошо написанной библиотеки, а у вас есть собственная плохо написанная библиотека C ++.
источник
На самом деле C # не работает на виртуальной машине, как Java. IL компилируется в язык ассемблера, который является полностью собственным кодом и выполняется с той же скоростью, что и собственный код. Вы можете выполнить предварительную JIT-компиляцию для .NET-приложения, которая полностью устранит затраты на JIT, и тогда вы будете запускать полностью собственный код.
Замедление с .NET произойдет не потому, что код .NET работает медленнее, а потому, что он делает гораздо больше за кулисами для таких вещей, как сбор мусора, проверка ссылок, сохранение полных кадров стека и т. Д. Это может быть довольно мощным и полезным, когда создание приложений, но также требует затрат. Обратите внимание, что вы можете делать все это и в программе на C ++ (большая часть основных функций .NET на самом деле является кодом .NET, который вы можете просматривать в ROTOR). Однако, если вы вручную написали ту же функциональность, вы, вероятно, в конечном итоге получили бы гораздо более медленную программу, поскольку среда выполнения .NET была оптимизирована и точно настроена.
Тем не менее, одна из сильных сторон управляемого кода состоит в том, что он может быть полностью проверяемым, т.е. вы можете убедиться, что код никогда не будет обращаться к памяти других процессов или делать что-то нестандартное, прежде чем вы его выполните. У Microsoft есть исследовательский прототип полностью управляемой операционной системы, который неожиданно показал, что 100% управляемая среда на самом деле может работать значительно быстрее, чем любая современная операционная система, за счет использования этой проверки для отключения функций безопасности, которые больше не нужны управляемым программам. (в некоторых случаях мы говорим как 10x). У SE Radio есть отличный эпизод, рассказывающий об этом проекте.
источник
В некоторых случаях управляемый код может быть быстрее, чем собственный код. Например, алгоритмы сборки мусора «отметка и очистка» позволяют средам, таким как JRE или CLR, освобождать большое количество недолговечных (обычно) объектов за один проход, при этом большинство объектов кучи C / C ++ освобождаются по очереди. время.
Из википедии :
Тем не менее, я написал много C # и много C ++, и я провел много тестов. По моему опыту, C ++ намного быстрее , чем C #, двумя способами: (1) если взять какой - то код , который вы написали в C #, портирование на C ++ нативный код , как правило , быстрее. Насколько быстрее? Что ж, он сильно различается, но нередко можно увидеть улучшение скорости на 100%. (2) В некоторых случаях сборка мусора может значительно замедлить работу управляемого приложения. .NET CLR ужасно справляется с большими кучами (скажем,> 2 ГБ) и может в конечном итоге проводить много времени в сборке мусора - даже в приложениях, которые имеют мало - или даже не имеют - объектов со средней продолжительностью жизни.
Конечно, в большинстве случаев, которые я описал, управляемые языки достаточно быстры, в значительной степени, и компромисс между обслуживанием и кодированием для дополнительной производительности C ++ просто не лучший.
источник
Вот интересный тест http://zi.fi/shootout/
источник
На самом деле JVM Sun HotSpot использует "смешанный режим" выполнения. Он интерпретирует байт-код метода до тех пор, пока не определит (обычно через какой-то счетчик), что конкретный блок кода (метод, цикл, блок try-catch и т. Д.) Будет выполняться много раз, а затем JIT компилирует его. Время, необходимое для JIT-компиляции метода, часто занимает больше времени, чем если бы метод должен был быть интерпретирован, если это редко запускаемый метод. Производительность обычно выше для «смешанного режима», потому что JVM не тратит время на JIT-код, который редко, если вообще запускается. C # и .NET этого не делают. .NET JIT использует все, что часто тратит время.
источник
Прочтите о Dynamo от HP Labs , интерпретаторе для PA-8000, который работает на PA-8000 и часто запускает программы быстрее, чем изначально. Тогда это совсем не покажется удивительным!
Не думайте об этом как о «промежуточном шаге» - запуск программы уже включает в себя множество других шагов на любом языке.
Часто это сводится к:
у программ есть горячие точки, поэтому даже если вы медленнее выполняете 95% кода, который вам нужно запустить, вы все равно можете быть конкурентоспособными по производительности, если вы быстрее на горячих 5%
HLL знает о ваших намерениях больше, чем LLL, например C / C ++, и поэтому может генерировать более оптимизированный код (у OCaml даже больше, а на практике часто даже быстрее)
JIT-компилятор имеет много информации, которой нет у статического компилятора (например, фактические данные, которые у вас есть на этот раз)
JIT-компилятор может выполнять оптимизацию во время выполнения, которую традиционным компоновщикам на самом деле не разрешено делать (например, переупорядочивание веток, чтобы общий случай был плоским, или встраивание вызовов библиотеки)
В общем, C / C ++ - довольно плохие языки с точки зрения производительности: относительно мало информации о ваших типах данных, нет информации о ваших данных и нет динамической среды выполнения, которая позволяла бы многое в плане оптимизации времени выполнения.
источник
Вы можете получить короткие всплески, когда Java или CLR быстрее, чем C ++, но в целом производительность будет хуже для всего срока службы приложения: см. Www.codeproject.com/KB/dotnet/RuntimePerformance.aspx для некоторых результатов для этого.
источник
Вот ответ от Cliff Click: http://www.azulsystems.com/blog/cliff/2009-09-06-java-vs-c-performanceagain
источник
Это нелогично. Использование промежуточного представления по своей сути не снижает производительность. Например, llvm-gcc компилирует C и C ++ через LLVM IR (который представляет собой виртуальную машину с бесконечными регистрами) в собственный код и обеспечивает отличную производительность (часто превосходящую GCC).
Вот некоторые примеры:
Виртуальные машины с JIT-компиляцией облегчают генерацию кода времени выполнения (например,
System.Reflection.Emit
в .NET), поэтому вы можете компилировать сгенерированный код на лету на таких языках, как C # и F #, но должны прибегать к написанию сравнительно медленного интерпретатора на C или C ++. Например, для реализации регулярных выражений.Части виртуальной машины (например, барьер записи и распределитель) часто пишутся вручную на ассемблере, потому что C и C ++ не генерируют достаточно быстрый код. Если программа нагружает эти части системы, она может превзойти все, что может быть написано на C или C ++.
Для динамического связывания собственного кода требуется соответствие ABI, что может снизить производительность и исключает оптимизацию всей программы, тогда как связывание обычно откладывается на виртуальных машинах и может извлечь выгоду из оптимизации всей программы (например, обобщенных дженериков .NET).
Я также хотел бы затронуть некоторые проблемы с ответом paercebal, получившим большое количество голосов выше (потому что кто-то продолжает удалять мои комментарии к его ответу), который представляет контрпродуктивно поляризованное мнение:
Следовательно, метапрограммирование шаблона работает только в том случае, если программа доступна во время компиляции, что часто бывает не так, например, невозможно написать конкурентоспособную библиотеку регулярных выражений на ванильном C ++, потому что она неспособна генерировать код во время выполнения (важный аспект метапрограммированием).
В C # это верно только для ссылочных типов и неверно для типов значений.
Люди наблюдали, как Java превосходит C ++ в тесте SOR из теста SciMark2 именно потому, что указатели препятствуют оптимизации, связанной с алиасингом.
Также стоит отметить, что .NET выполняет специализацию типов универсальных шаблонов в динамически связанных библиотеках после связывания, тогда как C ++ не может этого сделать, поскольку шаблоны должны быть разрешены перед связыванием. И очевидно, что большое преимущество дженериков перед шаблонами - это понятные сообщения об ошибках.
источник
Помимо того, что говорили некоторые другие, насколько я понимаю, .NET и Java лучше выделяют память. Например, они могут сжимать память, поскольку она фрагментируется, в то время как C ++ не может (изначально, но может, если вы используете умный сборщик мусора).
источник
Для всего, что требует большой скорости, JVM просто вызывает реализацию на C ++, поэтому вопрос больше в том, насколько хороши их библиотеки, чем в том, насколько хороша JVM для большинства вещей, связанных с ОС. Сборка мусора сокращает вашу память вдвое, но использование некоторых из более привлекательных функций STL и Boost будет иметь тот же эффект, но с во много раз большим потенциалом ошибок.
Если вы просто используете библиотеки C ++ и множество его высокоуровневых функций в большом проекте со множеством классов, вы, вероятно, закончите работу медленнее, чем при использовании JVM. За исключением гораздо большего количества ошибок.
Однако преимущество C ++ заключается в том, что он позволяет вам оптимизировать себя, иначе вы застрянете на том, что делает compiler / jvm. Если вы создаете свои собственные контейнеры, пишете собственное управление памятью, которое выровнено, используете SIMD и переходите к сборке здесь и там, вы можете ускорить, по крайней мере, в 2-4 раза по сравнению с тем, что большинство компиляторов C ++ делают самостоятельно. Для некоторых операций 16x-32x. Это с использованием тех же алгоритмов, если вы используете лучшие алгоритмы и распараллеливаете, увеличение может быть значительным, иногда в тысячи раз быстрее, чем обычно используемые методы.
источник
Я смотрю на это с нескольких разных точек зрения.
источник
Очень короткий ответ: при фиксированном бюджете вы добьетесь более высокой производительности Java-приложения, чем приложение C ++ (соображения рентабельности инвестиций). Кроме того, платформа Java имеет более достойные профилировщики, которые помогут вам быстрее определять точки доступа.
источник