Насколько C++ быстрее, чем C#?

Или сейчас все наоборот?

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

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

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

Robert Harvey 10.05.2011 22:13

Как это вообще не закрыто как мнение / аргумент? Разве я все еще не на StackOverflow? (Не предлагаю близких, просто любопытно. Я люблю вопросы, которые вызывают самоуверенные споры)

Bill K 02.03.2018 02:27

Это почти спорный вопрос, учитывая, что мы живем в эпоху, когда IL можно преобразовать в CPP и оттуда оптимизировать: docs.unity3d.com/Manual/IL2CPP.html

pixelpax 02.04.2018 20:22

Язык, который проверяет доступ к массиву вне диапазона, никогда не превзойдет язык, который этого не делает.

Seva Alekseyev 04.03.2020 01:02

@SevaAlekseyev Это делает не язык, а компилятор. Одна из причин того, что C++ так быстр (помимо очевидных), заключается в том, что компиляторы C++ существуют уже 35 лет (если не больше). Нет ничего, что мешало бы компиляторам C# со временем становиться лучше. В случае упомянутого вами случая, пожалуйста, прочтите этот stackoverflow.com/questions/16713076/…

Trap 04.03.2020 13:42
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
264
5
176 383
29
Перейти к ответу Данный вопрос помечен как решенный

Ответы 29

Это на пять апельсинов быстрее. Вернее: не может быть (правильного) общего ответа. C++ - это статически компилируемый язык (но есть еще и оптимизация, управляемая профилем), C# запускается с помощью JIT-компилятора. Существует так много различий, что на такие вопросы, как «насколько быстрее», невозможно ответить, даже если дать порядки величин.

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

Alex 02.01.2010 11:59

На дрожжах он не молчит, а закуска на порядок быстрее.

Chris 31.03.2010 18:06

По моему опыту, это скорее 5,2 апельсина. Но это зависит от того, какой фруктовый метр вы используете.

Dio F 22.10.2013 09:15

Обновление, сам StackOverflow испортился и обрабатывает комментарии неэффективно, поэтому бананов меньше (300 бананов хуже, чем должно быть): meta.stackexchange.com/questions/254534/…

KeksArmee 02.03.2016 23:07
Ответ принят как подходящий

Нет строгой причины, по которой язык на основе байт-кода, такой как C# или Java, который имеет JIT, не может быть таким же быстрым, как код C++. Однако код C++ долгое время был значительно быстрее, и во многих случаях он все еще работает сегодня. В основном это связано с тем, что более продвинутые JIT-оптимизации сложно реализовать, а действительно интересные из них появляются только сейчас.

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

С другой стороны, код на интерпретируемых языках становится быстрее в более поздних версиях среды выполнения (.NET CLR или Java VM) без каких-либо действий. И есть много полезных оптимизаций, которые могут выполнять JIT-компиляторы, которые просто невозможны в языках с указателями. Кроме того, некоторые утверждают, что сборка мусора, как правило, должна быть такой же быстрой или быстрой, как ручное управление памятью, и во многих случаях это так. Обычно вы можете реализовать и достичь всего этого на C++ или C, но это будет намного сложнее и подвержено ошибкам.

Как сказал Дональд Кнут, «преждевременная оптимизация - корень всех зол». Если вы действительно знаете наверняка, что ваше приложение будет в основном состоять из арифметических операций, критичных к производительности, и что это будет узкое место, и оно, безусловно, будет быстрее в C++, и вы уверены, что C++ не будет конфликтовать с другими требования, переходите на C++. В любом другом случае сконцентрируйтесь на том, чтобы сначала правильно реализовать свое приложение на том языке, который вам больше подходит, затем найдите узкие места в производительности, если оно работает слишком медленно, а затем подумайте о том, как оптимизировать код. В худшем случае вам может потребоваться вызвать код C через интерфейс внешней функции, чтобы у вас по-прежнему была возможность писать критические части на языке более низкого уровня.

Имейте в виду, что относительно легко оптимизировать правильную программу, но гораздо сложнее исправить оптимизированную программу.

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

<quote> код на интерпретируемых языках становится быстрее в более поздних версиях среды выполнения </quote> Поскольку код, скомпилированный лучшей версией компилятора, также станет быстрее.

Martin York 26.09.2008 13:44

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

tzot 26.09.2008 13:50

На самом деле есть по крайней мере одна причина: JIT должен быть быстрым и не может позволить себе тратить время на различные расширенные оптимизации, доступные для компилятора C++.

Nemanja Trifunovic 26.09.2008 18:04

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

Martin Probst 29.09.2008 18:18

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

Cristián Romo 08.10.2008 20:54

«но также часто приводит к ошибкам из-за чрезмерной оптимизации». [ссылка крайне необходима]. Я работаю в национальной лаборатории, и мы чертовски оптимизируем наш код. Обычно это не приводит к ошибкам в коде.

Todd Gamblin 11.12.2008 16:52

@martinprobst "с большим скептицизмом" - нет, не скептицизмом. Соответствующее отношение - любопытство - см. FAQ по тестам игры «Flawed Benchmarks».

igouy 21.02.2009 20:41

«Относительно легко оптимизировать правильную программу, но гораздо труднее исправить оптимизированную программу».

gradbot 17.07.2010 20:33

@Matin York: Но новый JIT также может быстрее выполнять старые сборки, новый компилятор бесполезен без новой компиляции;)

Aidiakapi 04.03.2011 00:48

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

user152949 21.01.2013 18:38

.. чтобы уточнить: компилятор C# и .NET CLR & CLI запрограммированы на C++.

user152949 21.01.2013 18:47

Инге: Не уверена, что ты на правильном пути. Да, C# реализован на другом языке, но JIT-компилятор генерирует машинный код, поэтому это не интерпретируемый язык. Таким образом, он не ограничен своей реализацией на C++. Я не совсем уверен, почему вы думаете, что добавление какого-либо менеджера к чему-то по сути делает его быстрее.

Martin Probst 26.01.2013 16:59

@NemanjaTrifunovic: «JIT должен быть быстрым, и он не может позволить себе тратить время на различные расширенные оптимизации, доступные для компилятора C++». Об этом часто говорят, но я никогда не видел никаких доказательств этого. Вы можете привести конкретные примеры такой оптимизации?

J D 02.11.2013 20:44

@Aidiakapi JIT означает, что у вас есть компилятор во время выполнения. Нет причин не перекомпилировать программу C++ с новым компилятором.

eonil 09.05.2014 14:23

@Eonil За исключением того, что требуется передислокация? Что касается серверных систем, обязательно перекомпилируйте программное обеспечение с помощью более современных компиляторов, которые имеют более продвинутую оптимизацию. Но для потребительского рынка это обычно невозможно, пока не будет выпущена новая версия. С .NET программа, скомпилированная 8 лет назад, может внезапно стать быстрее из-за оптимизации в новой .NET Framework.

Aidiakapi 09.05.2014 15:35

Что вы думаете о новом компиляторе C# roslyn? Я слышал, что это действительно значительно ускоряет код

Arsalan Ahmad 16.06.2014 09:35

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

Aidiakapi 13.07.2015 23:25

на самом деле главное в том, что некоторые вещи не могут быть эффективно реализованы на C#, но могут быть эффективно реализованы на C++, например. AMP Может быть, это временно, но сейчас это так.

AndersK 29.12.2015 04:08

[Дональд Э. Кнут, 2008-04-25] «X» может создавать тысячи двоичных файлов, идеально настроенных на конфигурации отдельных пользователей, тогда как «Y» обычно существует только в нескольких версиях. Стандартный двоичный исполняемый файл должен включать такие вещи, как неэффективные инструкции «синхронизации», которые совершенно не подходят для многих установок; такие потери исчезают, когда исходный код легко настраивается. Это должно стать огромной победой для «Х».

Johan Boulé 08.05.2016 01:56

Я бы сказал, что это больше, чем байт-код против нативного, это также касается самого языка, если язык недостаточно выразителен (и я думаю, что и C#, и Java подходят к этой категории), чтобы эффективно выражать вещи для бэкэнда, вы собираетесь проиграть независимо от того, ваш родной код или байт-код / ​​IL и т. д., родные языки тоже могут быть медленными; Я лично считаю, что байт-код имеет больше достоинств, чем должен, и по большей части все должно быть родным, родное тоже может быть использовано; это также о том, как далеко вам нужно идти, действительно ли вам нужно все до последнего цикла? иногда да, в большинстве случаев нет

user90843 02.07.2016 10:20

@AndersK. Это не было правдой, даже когда вы это разместили. Он обычно не используется, но .NET уже некоторое время поддерживает AMP, и AFAIK JVM тоже поддерживает его. Не забывайте, что C# отлично справляется с неуправляемой памятью и указателями - это немного больше работы, чем в C++ (фактически, немного похоже на C). Если вам нужен управляемый код и C++, Managed C++ дает вам и то, и другое одновременно (хотя, очевидно, собственная часть кода не является мультиплатформенной). А .NET делает взаимодействие чрезвычайно простым, поэтому вы всегда можете перейти на собственный C++, если вам нужно. Или VB6, что угодно, что плавает ваша лодка.

Luaan 14.07.2016 11:02

@Luuan Я думаю, что видел, что в каком-то старом интервью, касающемся инициативы "Native C++", я не помню точно, кто и когда, так что вы, вероятно, правы.

AndersK 14.07.2016 14:49

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

Ferruccio 08.09.2016 23:20

Когда вы упомянули об этом: «И есть много полезных оптимизаций, которые могут выполнять JIT-компиляторы, которые просто невозможны в языках с указателями», вы имели в виду оптимизацию, связанную с псевдонимом?

Jose Fernando Lopez Fernandez 29.06.2017 09:14
«Нет строгой причины, по которой язык на основе байт-кода, такой как C# или Java, который имеет JIT, не может быть таким же быстрым, как код C++». Sure there is. For one thing, JIT compilers have more limited time in which to compile the code than AoT compilers. That's enough to put them at a disadvantage.
user541686 22.03.2018 01:27

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

Ylisar 07.06.2018 16:04

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

Sturla Molden 07.05.2020 23:29

Ваши аргументы слишком общие и по большей части неуместны. Вам не нужно стремиться к написанию кода C++ стандартным образом, чтобы программа работала слишком быстро с небольшим объемом памяти. А если вам нужно оптимизировать код C++, у вас есть прямой доступ к огромному количеству оптимизаций, которые будет сложно превзойти другие языки; в лучшем случае просто подражание. Компилятор прилагает гигантские усилия, потому что у него есть время для этого, как для внутренних, так и для внутренних модулей. И он очень, очень силен в обеспечении абстракций с нулевой стоимостью из-за всего того, что, как известно, статично во время компиляции /

J. Bailleul 12.03.2021 02:39

Как обычно, это зависит от приложения. Есть случаи, когда C#, вероятно, незначительно медленнее, и другие случаи, когда C++ в 5 или 10 раз быстрее, особенно в случаях, когда операции можно легко выполнить SIMD.

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

J D 07.09.2011 00:13

Примечание из будущего: .NET поддерживает SIMD и друзей примерно с 2014 года, хотя широко не используется.

Luaan 14.07.2016 11:29

C# не может быть быстрее, но он делает ВАС / МЕНЯ быстрее. Это самая важная мера того, что я делаю. :)

Ха-ха, есть хорошая цитата Ларри Уолла по этой теме. Он говорит о Perl, но его можно рассматривать во всех обсуждениях, касающихся языков и производительности: «... более ранние компьютерные языки, такие как Fortran и C, были разработаны для эффективного использования дорогостоящего компьютерного оборудования. В отличие от Perl, Perl предназначен для эффективно использовать дорогих программистов »

Falaina 08.08.2009 09:05

1. «C# намного быстрее, чем C++» 2. «Это не может быть правдой» 1. «Конечно, может» 2. «Насколько?» 1. «Обычно на 3-4 месяца»

Dmitry S. 03.10.2015 00:19

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

user90843 02.07.2016 10:17

По той же причине вы можете использовать Python вместо C для написания кода ... но после выполнения некоторых сложных вычислений вы можете почувствовать разницу в производительности.

Ch3shire 07.01.2017 01:16

Это зависит от того, к чему вы привыкли. Я программирую на C++ намного быстрее, чем на C#. Знание библиотеки - большая часть этого, поскольку вы не хотите изобретать велосипед для основных задач. Основной проблемой C / C++ было управление указателями, которое в значительной степени решается с помощью интеллектуальных указателей. Сказав, что C++ серьезно не хватает обширной библиотеки, которую предлагает .NET и Java, и это может значительно ускорить разработку. Эта проблема не будет решена в ближайшее время, поскольку эти парни из стандартного отдела любят тратить свое время на улучшение шаблонов, а не на расширения библиотеки.

gast128 26.02.2020 12:02

gast128 - Вы отметили несколько хороших моментов. Я все еще согласен со своим ответом 12 лет назад;)

mattlant 27.02.2020 14:37

Вы программируете только один раз. Программу можно использовать миллионы раз. Что должно быть важнее?

Rodrigo 24.05.2020 06:37

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

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

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

В таких случаях (и, по общему признанию, они часто ограничиваются особыми проблемными областями) C++ побеждает C# и сопоставимые языки.

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

Martin Probst 29.09.2008 18:21

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

Konrad Rudolph 02.10.2008 19:50

+1 Мне всегда сложно объяснить это моим коллегам по C#, которые мало знают C++, так, чтобы они могли оценить значение. Вы довольно хорошо это объяснили.

Roman Starkov 15.09.2010 04:33

Но когда я собираю код от нескольких владельцев, я считаю, что экземпляры шаблонов очень трудно разделить через границы модуля. Я говорю о совместном использовании общего кода, такого как List <T> или vector <T>, во многих модулях приложения. Таким образом, для составных систем (много модулей, много владельцев) среды выполнения, такие как CLR, начинают компенсировать фиксированные накладные расходы за счет уменьшения нагрузки на кэш ЦП с помощью множества копий экземпляров одних и тех же шаблонов. Я думаю, что со временем лидерство в производительности C++ сократится, пока не останутся только нишевые библиотеки и нетипизированные библиотеки C.

yzorg 16.09.2010 13:21

@crtracy: вы делаете ставку без высокопроизводительных вычислительных приложений. Рассмотрите прогноз погоды, биоинформатику и численное моделирование. Лидерство C++ в производительности в этих областях сократится, поскольку ни один другой код не может достичь сопоставимой производительности на том же уровне высокой абстракции.

Konrad Rudolph 16.09.2010 17:24

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

J D 02.11.2013 21:02

@Jon Тогда используйте лучший движок регулярных выражений в C++ (его может и не быть; но это не фундаментальное ограничение - но на самом деле такие движки являются есть, например Boost.Xpressive). Ваше второе утверждение смехотворно.

Konrad Rudolph 04.11.2013 14:57

Вы можете использовать такую ​​библиотеку, как LLVM, для динамической генерации собственного кода на C++, если хотите. Против этого нет языковых ограничений. Это была бы легальная реализация std :: regex.

Puppy 04.11.2013 15:01

@JonHarrop Между прочим, чтобы избежать недоразумений, я признаю, что метапрограммирование C# - это более могущественный, потому что вы можете использовать его во время выполнения. Я не согласен с вашим утверждением "на порядок быстрее", которое совершенно неверно.

Konrad Rudolph 04.11.2013 15:05

@DeadMG: Да, конечно. Вы можете быстро решить любую проблему на любом языке, сгенерировав собственный машинный код.

J D 05.11.2013 13:22

@KonradRudolph: "Я не согласен с вашим утверждением" на порядок быстрее ", которое совершенно неверно". Как вы думаете, насколько велика разница в производительности между интерпретатором и кодом, сгенерированным оптимизирующим компилятором? Я видел, как Mathematica работает в 100000 раз медленнее, чем C ...

J D 05.11.2013 17:20

@Jon Яблоки и апельсины. Ваше конкретное утверждение было «C# на порядки быстрее, чем C++ в контексте метапрограммирования», а не «использование предварительно скомпилированного кода на порядки быстрее, чем интерпретируемый код». Пока мы занимаемся этим, ваше утверждение о том, что генерация кода во время выполнения является «более общей», чем генерация кода во время компиляции, также явно неверно - у них обоих есть сильные и слабые стороны. Генерация кода во время компиляции использует систему типов для обеспечения безопасности статического типа - генерация кода во время выполнения не может этого сделать (может обеспечивает строгую безопасность типа, но не безопасность типа статический).

Konrad Rudolph 05.11.2013 19:10

@KonradRudolph: «ваше утверждение о том, что генерация кода во время выполнения является« более общей », чем генерация кода во время компиляции, также явно неверно». Генератор кода во время выполнения может обрабатывать как статически, так и динамически доступные программы, тогда как во время компиляции можно обрабатывать только статически доступные программы. «Генерация кода времени выполнения не может этого сделать». MetaOCaml - противоположный пример.

J D 05.11.2013 22:27

@Jon Это все хорошо, но чисто академично. Ни C++, ни C# этого сделать не могут. Все это обсуждение посвящено C# и C++.

Konrad Rudolph 05.11.2013 22:55

@KonradRudolph: Возможно, вы могли бы прокомментировать 13-кратную разницу в производительности, которую я описал здесь: stackoverflow.com/questions/19798653/c-vs-net-regex-performa‌ nce

J D 06.11.2013 00:48

на самом деле C# действительно включает способы встраивания ваших функций с помощью System.Runtime.CompilerServices; ... [MethodImpl (MethodImplOptions.AggressiveInlining)] void MyMethod (...)

user219279 12.04.2016 10:05

@ user3800527 Никто не спорит с этим, но я не знаю ни одной реализации .net, которая могла бы использовать это для встраивания, скажем, вызовов IComparer внутри цикла алгоритма сортировки. C++ может это сделать.

Konrad Rudolph 12.04.2016 21:49

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

user219279 13.04.2016 15:25

@ user3800527 Это не сработает, если алгоритм сортировки является общим и может вызываться с разными типами IComparer. В этом вся проблема, и она решается универсальными шаблонами времени компиляции C++ (= шаблонами).

Konrad Rudolph 13.04.2016 17:37

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

user219279 14.04.2016 10:10

@ user3800527 Думаю, вам не хватает смысла этого ответа. Конечно, вы можете обойти это, нарушив инкапсуляцию и переключившись на низкоуровневые структуры - вы можете писать ассемблер (почти) на любом языке. То, что делает C++ (почти) уникальным и уникально подходящим для высокопроизводительного программирования, заключается в том, что вы можете создавать абстракции высокий уровень, которые обходятся во время выполнения нет. Таким образом, вам не нужно писать код, похожий на ассемблер, на C++, чтобы получить превосходную производительность: хорошо написанный sort(arr, generic_comparer) будет так же эффективен, как рукописный цикл на C++. Этого никогда не будет на C#.

Konrad Rudolph 14.04.2016 18:07

Да, C++ может это сделать, и это здорово. Но не думайте, что .NET (или JVM) не может - насколько я знаю, прямо сейчас вы правы в том, что поддержки нет. Но в обоих случаях у вас уже есть JIT-компилятор, обходящий вызовы виртуальных методов, если вы в основном вызываете один и тот же метод. Расширение этого, чтобы разрешить встраивание тела виртуальных методов, очевидно, возможно - хотя я бы не стал задерживать дыхание, поскольку это не важно для большинства проектов, а обходной путь очень прост. Вместо этого мы можем ожидать улучшения абстракций более высокого уровня - например, более умные анонимные делегаты.

Luaan 14.07.2016 11:11

@Luaan Нет, это действительно невозможно. Что C++ может делать, а другие языки не могут, так это то, что даже если внешняя функция не встроена, внутренняя функция. Например, представьте себе метод Sort, который принимает аргумент comparator. В C++ этот comparator может быть встроен, даже если Sort не будет. Для перечисленных вами языков это принципиально возможно нет, и это ограничение дизайна, а не техническое, которое может исчезнуть в будущем.

Konrad Rudolph 14.07.2016 13:25

@KonradRudolph Вы недооцениваете тот факт, что среда выполнения может оптимизировать все, что пожелает, до тех пор, пока исполняющая программа не может заметить разницу (в одном потоке). Это вполне допустимая оптимизация для встраивания внутренней функции, хотя для этого, безусловно, потребуется гораздо более умный JIT, чем сейчас в .NET. Да, это произойдет во время выполнения, но в .NET достаточно метаданных, чтобы это стало возможным. А благодаря функциям компилятора времени выполнения мне довольно легко добавить это во время выполнения, не полагаясь на JIT-компилятор - с IL намного проще обращаться, чем со сборкой x86.

Luaan 14.07.2016 15:48

@Luaan Вы путаете законное с тем, что технически возможно. C++ может это делать только потому, что он генерирует отдельную внешнюю функцию для каждого типа шаблона (подробности см. В stackoverflow.com/a/13722515/1968): сама функция помечена (статическим) типом. В .NET внешняя функция не помечена отдельными типами, ни статическими, ни динамическими. Чтобы сгенерировать для него отдельный код на основе разных параметров, оптимизатору пришлось бы решить проблему, которая, насколько мне известно, несговорчивый.

Konrad Rudolph 14.07.2016 16:26

@Luaan И, чтобы уточнить: это я не имею в виду, что абсолютно невозможно выполнить эту оптимизацию (что, очевидно, глупо), просто невозможно сделать это за разумное время (= постоянная временная сложность в отношении сложности выражения ) - что имеет значение при оценке возможности выполнения данной оптимизации во время выполнения.

Konrad Rudolph 14.07.2016 16:32

@KonradRudolph О, но это не обязательно тот же метод. Фактически, это уже происходит сейчас, например, с дженериками .NET. А поскольку у вас есть удостоверение делегата, это можно сделать так же эффективно, как и шаблоны. Не забывайте, что JIT-компилятор имеет дело с IL, который является «ассемблером» очень высокого уровня - в нем содержится масса информации. Не поймите меня неправильно - это определенно намного более простая проблема с шаблонами C++, и, как я уже сказал, я не ожидаю, что такая оптимизация когда-либо будет реализована для .NET, поскольку вместо этого они могут реализовать гораздо больше полезных вещей.

Luaan 14.07.2016 16:35

@Luaan Извинения, я отвлекся на мой собственный пример, где Sort не был универсальным методом в моем понимании. Вы правы, в .NET у него есть должным образом отдельный тип, если это универсальный (не уверен в Java, в которой все-таки нет повторных универсальных шаблонов… но, возможно, среда выполнения все равно отслеживает эти данные). Да, ты прав.

Konrad Rudolph 14.07.2016 16:38

@KonradRudolph Да, в Java дженерики - это не более чем синтаксический сахар. В .NET они также являются фактом времени выполнения - хотя я, конечно, иногда хотел, чтобы в C# были шаблоны C++ :) Но я думаю, что есть несколько примеров в JVM / JRE, где используется более мощная система цитат для создания всего кода в данные, очень похоже на LISP - может быть, Clojure? В этом случае все косвенные ссылки могут быть удалены в любое время во время выполнения, что должно позволить такой встраиванию работать идеально, задолго до того, как вам придется заботиться о таких сложностях, как локальные слоты данных.

Luaan 14.07.2016 16:50

C++ (или C, если на то пошло) дает вам детальный контроль над вашими структурами данных. Если вы хотите немного покрутиться, у вас есть такая возможность. Большие управляемые приложения Java или .NET (OWB, Visual Studio 2005), которые используют внутренние структуры данных библиотек Java / .NET, несут с собой багаж. Я видел сеансы дизайнера OWB, использующие более 400 MB ОЗУ, и BIDS для дизайна куба или ETL также попадали в сотню МБ.

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

IMO для больших приложений разница не столько в JIT, сколько в структурах данных, которые использует сам код. Если приложение требует много памяти, вы получите менее эффективное использование кеша. Промахи кеша на современных процессорах обходятся довольно дорого. Где C или C++ действительно выигрывают, так это там, где вы можете оптимизировать использование структур данных, чтобы хорошо работать с кешем ЦП.

Это чрезвычайно расплывчатый вопрос, на который нет однозначных ответов.

Например; Я лучше поиграю в 3D-игры, созданные на C++, чем на C#, потому что производительность, безусловно, намного лучше. (И я знаю XNA и т. д., Но это далеко не настоящая вещь).

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

Не могли бы вы назвать несколько примеров? Игры, написанные на C#, которые вы считаете медленными

Karl 26.09.2008 18:10

Даже примеры приложений, поставляемые с установкой, работали медленно.

David The Man 30.09.2008 09:35

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

postfuturist 31.10.2008 01:44

Большинство современных игр ограничены графическим процессором. Для таких игр не имеет значения, если логика (выполняемая на CPU) на 10% медленнее, они по-прежнему ограничены графическим процессором, а не CPU. Сборщик мусора - реальная проблема, вызывающая случайные короткие зависания, если распределение памяти не настроено должным образом.

Michael Entin 26.11.2008 21:05

@postfuturist: На ПК это не так; сборщик мусора так хорошо справляется с входом и выходом, что я никогда не испытывал с ним никаких проблем. Однако на XBox 360 и Zune / Windows-7-Phone сборщик мусора Около не такой умный, как на ПК; Я никогда не писал ни того, ни другого, но люди, у которых есть говорит мне, что сборщик мусора - это проблема огромный.

BlueRaja - Danny Pflughoeft 02.06.2011 02:06

@BlueRaja Есть отличная статья, который объясняет, как и когда сборщики мусора работают медленно. При достаточно высокой нехватке памяти они могут работать медленно даже на ПК. Я не знаю требований точный для игр AAA, но нетрудно представить, что они выходят за рамки, в которых современный GC работает хорошо.

Konrad Rudolph 06.11.2013 03:20

@KonradRudolph Хотя игры часто используют много памяти, большая ее часть может оставаться нетронутой. Особенно с загрузочными экранами много данных извлекается с жесткого диска, помещается в оперативную память, передается на видеокарту, а некоторые из них могут быть восстановлены. Путем принудительного полного сбора ГХ после этой фазы загрузки можно сбросить большое давление во время работы. Общие проблемы с производительностью игры возникают из-за того, что требуется много вычислительной мощности в короткие сроки, в то время как у других есть лишняя. GC довольно хорошо определяет, когда у вас есть запасные, и попытается собрать их в этих кадрах.

Aidiakapi 09.05.2014 16:11

@Aidiakapi Чтобы не противоречить вам в принципе, но когда (в игровом цикле в обычное время игры) давление настолько меньше, что большая коллекция может работать, не влияя на восприятие? Кроме того, даже если память остается нетронутой, она все равно должна быть доступна. Возможно, повсеместное использование слабых ссылок (для реализации кеша и перезагрузки из вторичной памяти после сбора) могло бы помочь, но сборщики мусора работают хорошо только тогда, когда доступно гораздо больше памяти, чем используется. И, наконец, одна вещь в теории: на практике какой современный сборщик мусора надежно выполняет то, что вы описали?

Konrad Rudolph 09.05.2014 17:26

@postfuturist Если вы правильно запрограммируете свою игру, вы вообще не будете использовать GC. Большинство типов данных и вычислений выполняются с помощью структур, а объекты обычно сохраняются в течение всего времени существования уровня. Когда уровень закончится, просто заставьте GC перед загрузкой следующего уровня. (Говоря в этом отношении о C#)

Krythic 01.01.2016 06:02

@Karl Я также постоянно видел, что игры, написанные на C#, медленные. Хотите верьте, хотите нет, но я действительно смотрю, была ли игра создана на C#, потому что я бы попытался избежать этого из-за соображений производительности, это так плохо. Лес, 7 дней до смерти, Broforce, план побега и так далее. Мне ДЕЙСТВИТЕЛЬНО нравится Broforce, поэтому я смирился с этим. По моему опыту, игры на C# неизменно выглядят очень медленными. Вполне возможно, что разработчики плохо поработали над оптимизацией. Однако C# - один из моих любимых языков, но он довольно медленный для приложений реального времени.

Richmar1 05.03.2019 05:55

По моему опыту (а я много работал с обоими языками), основная проблема C# по сравнению с C++ - это высокое потребление памяти, и я не нашел хорошего способа его контролировать. Это было потребление памяти, которое в конечном итоге замедлило работу программного обеспечения .NET.

Другой фактор заключается в том, что JIT-компилятор не может уделять слишком много времени расширенной оптимизации, потому что он работает во время выполнения, и конечный пользователь заметит это, если это займет слишком много времени. С другой стороны, у компилятора C++ есть все время, необходимое для оптимизации во время компиляции. ИМХО, этот фактор гораздо менее значим, чем потребление памяти.

В одном рабочем проекте нам приходилось добывать гигантские объемы данных, включая одновременное хранение большого количества ГБ в памяти и выполнение дорогостоящих вычислений над всем этим - это требовало точного контроля над всеми выделениями, C++ был практически единственным выбором. +1 для C++. С другой стороны, это был всего лишь один проект, мы потратили большую часть времени на написание систем, которые взаимодействуют с медленными симуляторами, а отладка могла быть кошмаром, поэтому мне хотелось, чтобы мы могли использовать язык, оптимизирующий время программиста, для всего остального. вещи.

Bogatyr 09.09.2011 14:24

Вы можете принудительно удалить объекты из управляемой кучи. См. msdn.microsoft.com/en-us/library/… для получения дополнительной информации.

user152949 21.01.2013 18:49

@IngeHenriksen: Я хорошо знаю шаблон Dispose, но он совсем не помогает с управляемой памятью.

Nemanja Trifunovic 21.01.2013 22:21

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

doug65536 29.01.2013 21:52

@NemanjaTrifunovic: «JIT-компилятор не может уделять слишком много времени продвинутой оптимизации». Можете ли вы указать на некоторые оптимизации, которые не выполняются JIT, потому что они занимают слишком много времени?

J D 02.11.2013 20:53

Но в наши дни память также дешевая, более серьезная проблема - добавить 32 ГБ или вместо этого позволить кому-то кодировать на несколько месяцев больше на C++ (большой проект) по сравнению с C#.

user219279 13.04.2016 15:29

@ user3800527: Даже если добавление ОЗУ всегда было возможным (а это не так - представьте, что Microsoft добавляет ОЗУ каждому пользователю MS Office), это не решит проблему. Память является иерархической, и программа на C# будет иметь гораздо больше промахов кеша, чем программа на C++.

Nemanja Trifunovic 13.04.2016 15:58

@ doug65536: Похоже, Dispose имеет какое-то отношение к управлению памятью ... Когда вы «очищаете неуправляемые ресурсы», память, содержащая эти ресурсы, освобождается, верно?

Joanna Marietti 31.08.2016 06:24

@JoannaMarietti Ну, да, но в конечном итоге эти ресурсы будут освобождены финализатором, даже если вы забудете вызвать Dispose. Забыть немедленно удалить файл, открытый исключительно, может быть серьезной проблемой, так как это может помешать его открытию в другом месте в течение неоправданного времени. Вы также можете случайно оставить блокировку файлов заблокированной. Утечки по-прежнему возможны с помощью сборщика мусора, если вы случайно сохраняете доступные ссылки без необходимости.

doug65536 02.09.2016 22:06

Спасибо, тот, кто на самом деле дает ответ, а не просто говорит «о, это зависит ... мля».

sebjwallace 29.11.2017 22:15

Я знаю, что это не то, о чем вы спрашивали, но C# часто быстрее написать, чем C++, что является большим преимуществом в коммерческой среде.

Я бы сказал, что в большинстве случаев это быстрее :)

Trap 27.09.2008 01:29

Я полагаю, что есть приложения, написанные на C#, которые работают быстро, а также есть другие приложения, написанные на C++, которые работают быстро (ну, C++ просто старше ... и возьмите UNIX тоже ...)
- вопрос действительно в том, на что жалуются пользователи и разработчики ...
Что ж, IMHO, в случае с C# у нас очень удобный интерфейс, очень красивая иерархия библиотек и вся система интерфейса CLI. В случае C++ у нас есть шаблоны, ATL, COM, MFC и весь набор уже написанного и работающего кода, такого как OpenGL, DirectX и так далее ... Разработчики жалуются на неопределенно возрастающие вызовы GC в случае C# (означает, что программа работает быстро, и за одну секунду - бац! застрял) .
Писать код на C# очень просто и быстро (не забывайте, что это также увеличивает вероятность ошибок. В случае с C++ разработчики жалуются на утечки памяти, - имеются в виду вылеты, вызовы между DLL, а также на «ад DLL» - проблема с поддержкой и заменой библиотек на более новые ...
Я думаю, что чем больше у вас навыков в языке программирования, тем больше качества (и скорости) будет характеризовать ваше программное обеспечение.

> Из того, что я слышал ...

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

Как вы собираетесь решить, более или менее достоверно то, о чем здесь говорят люди, чем то, что вы слышали изначально?

Один из способов - попросить свидетельство.

Когда кто-то заявляет, что «есть некоторые области, в которых C# оказывается быстрее, чем C++» спроси их Почему они говорят что, попросите их показать вам измерения, попросите их показать вам программы. Иногда они просто ошиблись. Иногда вы обнаруживаете, что они просто выражают мнение, а не делятся тем, что они могут показать, чтобы быть правдой.

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

  • "Возьмите тесты на http://shootout.alioth.debian.org/ с большим скептицизмом, поскольку это в основном тестовый арифметический код, что, скорее всего, не похоже на ваш код вообще. "

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

  • "Это довольно бесполезный тест, поскольку он действительно зависит от того, насколько хорошо индивидуальные программы были оптимизирован; Мне удалось ускорить некоторые из них в 4-6 раз и более, давая понять, что сравнение между неоптимизированными программами есть довольно глупо. "

    Спросите себя, есть ли у автора на самом деле показал вам, что ему удалось "ускорить некоторые из них на 4-6 раз и более »- это легко сделать!

Я не мог с вами больше согласиться, и именно поэтому я спросил на этом форуме ... В конце концов, ответы должны быть где-то, не так ли? :)

Trap 27.09.2008 01:39

да. Ответ: «Это зависит от обстоятельств».

user49117 30.12.2008 01:49

Для графики стандартный класс C# Graphics намного медленнее, чем GDI, доступ к которому осуществляется через C / C++. Я знаю, что это не имеет ничего общего с языком как таковым, больше с платформой .NET в целом, но графика - это то, что предлагается разработчику в качестве замены GDI, и ее производительность настолько плоха, что я бы даже не осмелился делать графику. с этим.

У нас есть простой тест, который мы используем, чтобы увидеть, насколько быстро работает графическая библиотека, и который просто рисует случайные линии в окне. C++ / GDI по-прежнему быстро обрабатывает 10000 строк, в то время как C# / Graphics с трудом выполняет 1000 строк в реальном времени.

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

Pedery 11.06.2012 03:02

@Pedery Нет, не знаю. просто используя GDI и .NET.Graphics самыми простыми способами. что вы подразумеваете под «самим рисованием случайных линий»?

QBziZ 03.07.2012 12:20

Тогда вам, возможно, стоит подумать о том, чтобы проверить это, чтобы получить более реалистичные показатели того, насколько быстрым может быть C#. Вот хороший обзор техники: bobpowell.net/lockingbits.htm

Pedery 10.07.2012 18:33

Мы не хотим этого делать, сами помещая отдельные пиксели в буфер кадра. Если вам нужно реализовать все самостоятельно, какой смысл иметь API / платформу для кодирования? Для меня это не аргумент. Нам никогда не приходилось помещать отдельные пиксели во фреймбуфер в GDI для рисования линий, и мы не планируем делать это и в .NET. На мой взгляд, мы использовали реалистичную метрику, и .NET оказался медленным.

QBziZ 18.07.2012 16:07

Это реалистично, поскольку иногда вам нужно ускорить графику, и вы можете сделать это, продолжая работать с C#. Я думаю, что интересно, что вы это протестировали, поэтому было бы еще интереснее посмотреть, работает ли метод блокировок C# так же быстро, как его аналоги на C++.

Pedery 23.07.2012 11:33

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

user219279 12.04.2016 10:00

Что ж, у меня есть лишь небольшое представление о том, что такое обнаружение blob, но просто указание одного момента времени ничего не доказывает. Вы написали один на C++? В JavaScript? И сравнивал их с тем, что написано на C#? Кроме того, я не думаю, что для обнаружения blob-объектов используются многие графические примитивы. Поправьте меня, если не прав, но я предполагаю, что это статистические алгоритмы, выполняющие операции с пикселями.

QBziZ 17.04.2016 13:07

@JonHarrop Эм? WPF не использует GDI или класс C# Graphics. И очень медленно по сравнению с чем? На каком железе? А как измерить "медленный"? И как C# WPF сравнивается с C++ WPF? Я согласен, например, MFC в C++ намного быстрее, чем Winforms в .NET, но WPF на самом деле несопоставим. Я легко могу иметь десятки тысяч элементов управления в WPF без виртуализации и при этом работать быстро - ни родной MFC, ни Winforms и близко не подходят.

Luaan 14.07.2016 11:17

> Ведь ответы где-то должны быть, не так ли? :)

Эмм, нет.

Как отмечалось в нескольких ответах, вопрос недооценен вызывает вопросы в ответ, а не ответы. Ехать только в одну сторону:

И какие тогда программы? Какая машина? Какая ОС? Какой набор данных?

Я полностью согласен. Интересно, почему люди ожидают точного ответа (63,5%), когда задают общий вопрос. Я не думаю, что на этот вопрос нет общего ответа.

call me Steve 25.11.2008 02:54

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

Wouter van Nifterick 06.11.2010 11:52

Кажется, это не отвечает на вопрос, а больше читается как комментарий или напыщенная речь.

Tas 17.06.2016 03:20

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

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

Сборка мусора - основная причина, по которой Java # НЕ МОЖЕТ использоваться в системах реального времени.

  1. Когда произойдет сборщик мусора?

  2. Как много времени это займет?

Это недетерминировано.

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

Zan Lynx 01.04.2010 10:47

Если хотите, существует множество реализаций сборки мусора в реальном времени. (GC - это область переполненный с исследовательскими работами)

Arafangion 19.05.2010 04:37

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

J D 07.09.2011 12:01

Просто говорить, что "есть RTGC" не отвечает на вопрос о детерминизме. Я считаю, что многие люди до сих пор сомневаются в этом из-за отсутствия реального ясного объяснения.

eonil 09.05.2014 14:42

Это бессмысленный аргумент, Windows (и Linux) - это не операционные системы реального времени. Ваш код C++ может быть заменен на несколько слотов по 18 мс в любое время.

Henk Holterman 17.05.2014 12:47

@HenkHolterman Верно, но вы всегда можете написать загрузчик в сборке, связать его с загрузкой ядра для своего приложения и выполнять свои приложения C++ непосредственно на оборудовании (в RT, кстати). Вы не можете сделать это на C#, и любые усилия, которые я видел, только имитируют предварительно скомпилированную сборку на C# и используют тонну кода C, что делает использование C# бессмысленным. Читать все это довольно забавно, потому что C# действительно бесполезен без .NET framework.

zackery.fix 12.01.2016 09:54

компьютеры в реальном времени - это оксюморон

user219279 12.04.2016 09:59

@ zackery.fix Ха-ха, нет. Я не говорю, что C# был бы моим первым выбором для встраиваемой системы с 32 КБ памяти, но это только потому, что нет особого смысла оптимизировать какую-либо часть C# или .NET для такой среды. Но если у вас есть хотя бы пол-мегабайта памяти, все в порядке. И раньше я писал ОС на C# и могу сказать вам, что это потрясающе. Конечно, без .NET framework. Забавно, как вы говорите, что C# может только «имитировать» предварительно скомпилированную сборку, тогда как в C++ вы получаете это изначально ... с помощью сборки. Так вы можете писать ОС на C++ или нет? :)

Luaan 14.07.2016 11:22

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

Нам нужно было определить, сопоставим ли C# с C++ по производительности, и я написал несколько тестовых программ для этого (используя Visual Studio 2005 для обоих языков). Оказалось, что без сборки мусора и только с учетом языка (а не фреймворка) C# имеет в основном ту же производительность, что и C++. Распределение памяти в C# происходит намного быстрее, чем в C++, а C# имеет небольшое преимущество в детерминированности, когда размеры данных увеличиваются за пределы строки кэша. Однако в конечном итоге за все это пришлось заплатить, и есть огромные затраты в виде недетерминированных падений производительности для C# из-за сборки мусора.

В C++ у вас есть возможность использовать разные методы распределения, поэтому в зависимости от того, как была выделена память (AOT?) В C#, это можно было сделать так же (но намного быстрее) в C++.

zackery.fix 12.01.2016 09:56

@ zackery.fix. У .NET есть интересное преимущество в распределении кучи, потому что ему нужно только переместить указатель, чтобы выделить новый объект. Это возможно только за счет уплотняющего сборщика мусора. Конечно, вы можете делать то же самое в C++, но C++ этого не делает. Забавно, как вы используете один и тот же аргумент, чтобы сказать: «C# может, но не может, так что это мусор» и «C++ не может, но может, так что это круто» :)

Luaan 14.07.2016 11:27

Что касается «досадно параллельных» проблем, при использовании Intel TBB и OpenMP на C++ я наблюдал примерно 10-кратное увеличение производительности по сравнению с аналогичными (чисто математическими) задачами, выполненными с C# и TPL. SIMD - это одна из областей, в которой C# не может конкурировать, но у меня также сложилось впечатление, что у TPL есть значительные накладные расходы.

Тем не менее, я использую C++ только для задач, критичных к производительности, когда я знаю, что смогу работать в многопоточном режиме и быстро получать результаты. Для всего остального подходит C# (а иногда и F#).

Вдохновленный этим, я провел быстрый тест с 60% общих инструкций, необходимых для большинства программ.

Вот код C#:

for (int i=0; i<1000; i++)
{
    StreamReader str = new StreamReader("file.csv");
    StreamWriter stw = new StreamWriter("examp.csv");
    string strL = "";
    while((strL = str.ReadLine()) != null)
    {
        ArrayList al = new ArrayList();
        string[] strline = strL.Split(',');
        al.AddRange(strline);
        foreach(string str1 in strline)
        {
            stw.Write(str1 + ",");
        }
        stw.Write("\n");
    }
    str.Close();
    stw.Close();
}

Для включения этих инструкций специально используются строковый массив и arrayylist.

Вот код на C++:

for (int i = 0; i<1000; i++)
{
    std::fstream file("file.csv", ios::in);
    if (!file.is_open())
    {
        std::cout << "File not found!\n";
        return 1;
    }

    ofstream myfile;
    myfile.open ("example.txt");
    std::string csvLine;

    while (std::getline(file, csvLine))
    {
        std::istringstream csvStream(csvLine);
        std::vector csvColumn;
        std::string csvElement;

        while( std::getline(csvStream, csvElement, ‘,’) )
        {
            csvColumn.push_back(csvElement);
        }

        for (std::vector::iterator j = csvColumn.begin(); j != csvColumn.end(); ++j)
        {
            myfile << *j << ", ";
        }

        csvColumn.clear();
        csvElement.clear();
        csvLine.clear();
        myfile << "\n";
    }
    myfile.close();
    file.close();
}

Я использовал размер входного файла 40 KB.

И вот результат -

  • Код C++ запускался за 9 секунд.
  • Код C#: 4 секунды !!!

О, но это было в Linux ... С C#, работающим на Мононуклеоз ... И C++ с g ++.

Хорошо, вот что у меня получилось в Windows - Visual Studio 2003:

  • Код C# был выполнен за 9 секунд.
  • Код на C++ - ужасные 370 секунд !!!

Здесь вы используете другие структуры данных и код библиотеки, хотя «370 секунд» действительно указывает на что-то ужасное - вы случайно не запускаете это в отладчике, не так ли? Я подозреваю, что производительность используемой вами библиотеки CSV более интересна, чем производительность используемого вами языка. Я бы поставил под сомнение использование вектора в этом контексте и какие оптимизации вы использовали. Кроме того, широко известно, что iostreams (в частности, «myfile << * j <<», «;») намного медленнее, чем другие методы записи в файл, по крайней мере для некоторых распространенных реализаций.

Arafangion 18.05.2010 07:14

Наконец, вы делаете больше работы в версии для C++. (Почему вы очищаете csvColumn, csvElement и csvLines?)

Arafangion 18.05.2010 07:14

Каждая итерация цикла while будет разрушать и восстанавливать std :: istream, std :: vector и std :: string. Тело while выходит за пределы области видимости на каждой итерации, все эти переменные внутри области видимости while будут разрушаться и строиться на каждой итерации.

doug65536 29.01.2013 22:45

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

Zachary Kraus 15.11.2014 13:13

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

user219279 12.04.2016 09:57

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

HumbleWebDev 21.07.2017 23:51

Вы вообще компилировали с включенной оптимизацией? 9 секунд против 370 секунд звучит маловероятно, если только MSVC не пропустил оптимизацию некоторых очень дорогих вещей, обнаруженных g ++.

Peter Cordes 07.04.2018 10:14

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

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

-1: На самом деле это миф. Во-первых, латентность идиоматического C++ на самом деле ужасна и часто намного хуже, чем у .NET, потому что RAII вызывает лавину деструкторов, когда большие структуры данных выпадают из области видимости, тогда как современные GC являются инкрементными, а .NET даже параллельны. Во-вторых, вы можете полностью удалить паузы сборщика мусора в .NET, не выделяя.

J D 07.09.2011 00:09

Если вы сделаете это, вам придется отказаться от использования BCL, поскольку большинство методов создают временные объекты.

Florian Doyon 07.09.2011 12:52

Это совершенно верно, только после .net 4 сборщик мусора стал инкрементным. У нас есть большое приложение на C#, которое приостанавливает сборку мусора на несколько секунд. Для приложений, критичных к производительности, это убийца.

Justin 11.11.2011 02:32

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

VoronoiPotato 30.10.2012 17:51

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

Krythic 01.01.2016 06:08

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

DAG 17.03.2016 08:20

@JonHarrop Просто переместите свои деструкторы в отдельный поток. Ушли в прошлое задержки.

Clearer 30.11.2017 13:16

@DAG: Верно, но вы, конечно, можете управлять поведением кеша на всех этих языках.

J D 16.12.2017 05:30

@Clearer: вы Greenspunning GC.

J D 16.12.2017 05:32

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

Clearer 18.12.2017 15:37

@Clearer: Значит, вы говорите, что вы не используете GC, потому что не используете «магию»?

J D 20.12.2017 23:21

@JonHarrop Любой правильный сборщик мусора будет просматривать всю выделенную память, чтобы выяснить, какие биты больше не достижимы, и затем восстановит эти биты. Это не то, что происходит, если вы переносите уничтожение объектов в другой поток; вы вручную заявляете, что эти биты безопасны для восстановления со всеми преимуществами и проблемами, которые у вас обычно есть, и без каких-либо (как ни в одном случае) преимуществ GC. Обычный GC воля вводит задержки в полуслучайных местах в вашей программе; обычно намного хуже, чем RAII, и намного менее предсказуемо.

Clearer 02.01.2018 16:50

@Clearer: «Любой надлежащий сборщик мусора будет просматривать всю выделенную память, чтобы выяснить, какие биты больше не достижимы, и затем они будут возвращены». Подсчет ссылок - очевидный пример счетчика. «Обычный сборщик мусора привнесет задержки в полуслучайные места в вашей программе; обычно намного хуже, чем RAII». Я когда-либо видел уменьшение задержки только при замене RAII на сборщик мусора, поэтому мне бы хотелось, чтобы эта гипотеза была проверена должным образом.

J D 03.01.2018 01:11

@JonHarrop Подсчет ссылок делает именно то, что я описал, иначе он может сломаться. У меня никогда не было значительных задержек, вызванных уничтожением объектов с использованием RAII; если вы видите уменьшение задержки с помощью сборщика мусора, я могу представить только один из следующих сценариев: (1) вы что-то не так (т. е. выделяете 1 объект 1000 раз, а не 1000 объектов за раз), (2) GC не делает то, что говорит вам (не очищает все) или (3) переносит разрушение в отдельный поток. Раньше я видел, как сборщики мусора переносят разрушение в новые потоки.

Clearer 03.01.2018 01:44

@Clearer: «Подсчет ссылок делает именно то, что я описал, иначе он может сломаться». Извините, но RC работает не так. Предлагаю прочитать gchandbook.org

J D 03.01.2018 17:32

@Clearer: «Я могу представить только один из следующих сценариев». Когда коллекции коллекций выпадают из области видимости, родительские деструкторы рекурсивно вызывают дочерние деструкторы до тех пор, пока не будет уничтожена вся группа DAG. Это сколь угодно долгая пауза. Инкрементальные сборщики мусора этого не делают.

J D 03.01.2018 17:38

C++: длительная фаза оптимизации, выполняется один раз перед запуском.

rxantos 10.09.2019 06:17

Смотря как. Если байт-код переводится в машинный код (а не только JIT) (я имею в виду, если вы выполняете программу) и, если ваша программа использует много распределений / освобождений, это может быть быстрее, потому что алгоритму GC нужен только один проход (теоретически) через всю память один раз, но обычные вызовы malloc / realloc / free C / C++ вызывают накладные расходы при каждом вызове (накладные расходы на вызовы, накладные расходы на структуру данных, промахи в кеше;)).

Так что теоретически это возможно (также для других языков GC).

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

Еще одним большим преимуществом является то, что SQL, как и «расширение» LINQ, предоставляет компилятору возможности для оптимизации вызовов к базам данных (другими словами, компилятор может скомпилировать весь LINQ в один двоичный двоичный объект, в котором вызываемые функции встроены или для вашего использования оптимизирован, но я размышляю здесь).

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

Clearer 03.01.2018 11:42

из любви к богам, этому 8 лет, OMFGz

Quonux 08.01.2018 23:28

не стесняйтесь дать более актуальный ответ

Quonux 08.01.2018 23:29

Я тестировал vector в C++ и эквиваленте C# - List и простых 2d-массивах.

Я использую редакции Visual C# / C++ 2010 Express. Оба проекта представляют собой простые консольные приложения, я тестировал их в стандартном (без пользовательских настроек) режиме выпуска и отладки. Списки C# работают быстрее на моем компьютере, инициализация массива также выполняется быстрее в C#, математические операции выполняются медленнее.

Я использую Intel Core2Duo P8600 @ 2,4 ГГц, C# - .NET 4.0.

Я знаю, что реализация вектора отличается от C# list, но я просто хотел протестировать коллекции, которые я бы использовал для хранения своих объектов (и возможность использовать средство доступа к индексу).

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

Векторный тест C++:

static void TestVector()
{
    clock_t start,finish;
    start=clock();
    vector<vector<double>> myList=vector<vector<double>>();
    int i=0;
    for( i=0; i<500; i++)
    {
        myList.push_back(vector<double>());
        for(int j=0;j<50000;j++)
            myList[i].push_back(j+i);
    }
    finish=clock();
    cout<<(finish-start)<<endl;
    cout<<(double(finish - start)/CLOCKS_PER_SEC);
}

Тест списка C#:

private static void TestVector()
{

    DateTime t1 = System.DateTime.Now;
    List<List<double>> myList = new List<List<double>>();
    int i = 0;
    for (i = 0; i < 500; i++)
    {
        myList.Add(new List<double>());
        for (int j = 0; j < 50000; j++)
            myList[i].Add(j *i);
    }
    DateTime t2 = System.DateTime.Now;
    Console.WriteLine(t2 - t1);
}

C++ - массив:

static void TestArray()
{
    cout << "Normal array test:" << endl;
    const int rows = 5000;
    const int columns = 9000;
    clock_t start, finish;

    start = clock();
    double** arr = new double*[rows];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    finish = clock();

    cout << (finish - start) << endl;

    start = clock();
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    finish = clock();

    cout << (finish - start) << endl;
}

C# - массив:

private static void TestArray()
{
    const int rows = 5000;
    const int columns = 9000;
    DateTime t1 = System.DateTime.Now;
    double[][] arr = new double[rows][];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    DateTime t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

    t1 = System.DateTime.Now;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

}

Время: (Выпуск / Отладка)

C++

  • Инициализация массива 600/606 мс,
  • Заполнение массива 200/270 мс,
  • 1сек / 13сек вектор инициализации и заполнения.

(Да, 13 секунд, у меня всегда проблемы со списками / векторами в режиме отладки.)

C#:

  • Инициализация массива 20/20 мс,
  • Заполнение массива 403/440 мс,
  • 710/742 мс список инициализации и заполнения.

Я бы хотел увидеть средство доступа к индексу в std :: list. В любом случае, это занимает 37 секунд со списком, режимом выпуска. Выпуск без отладки: список 3 с, вектор 0,3 с. Вероятно, проблема с разыменованием или что-то в этом роде. Пример: nopaste.pl/12fb

Wiory 23.06.2011 19:48

@ doug65536 да, я понимаю, что теперь, написав C#. Возможно, я просто вычеркну все это из истории ...

deceleratedcaviar 30.01.2013 11:59

@ Даниэль, хорошо, я тоже удалю свой комментарий.

doug65536 23.05.2013 20:10

Для более точных измерений вам следует использовать не System.DateTime.Now, а класс Секундомер.

Sam 25.08.2014 03:17

Одна из причин, по которой вы получаете такое медленное время заполнения вектора в C++, заключается в том, что вы используете push_back. Во многих сообщениях было показано, что это происходит медленнее, чем при использовании метода at или оператора []. Чтобы использовать любой из этих методов, вам необходимо использовать метод изменения размера или резервирования. Кроме того, причина, по которой ваша инициализация занимает так много времени для случая вектора С ++, заключается в том, что вы заставляете оператор копирования или присваивания (не уверен, какой в ​​данном случае) для инициализации вашего вектора С ++. Для массива в C++ существует алгоритм, который использует 2 новых вызова вместо 5001 и также быстрее повторяется.

Zachary Kraus 15.11.2014 12:55

Я думаю, вы не сделали C++ должным образом. Просто взглянул и обнаружил так много проблем. Например. вектор <вектор <двойной>> myList = вектор <вектор <двойной>> ()

DAG 17.03.2016 05:44

А вы заметили, сколько раз вы строили такой двумерный вектор? И не могли бы вы сделать резерв () для ускорения push_back ()? Думаю, ваш бенчмарк не имеет смысла. И то, как вы измеряете часы, тоже далеко не точное. Только мои 2 цента

DAG 17.03.2016 06:14

vector <vector <double>> myList = vector <vector <double>> () Я вижу, что разработчики C#, которые пишут на C++, делают это все время, это МЕДЛЕННО и БЕСПОЛЕЗНО, не делайте бессмысленных копий материала

paulm 11.07.2016 10:31

Это совершенно неверно. Я получаю совершенно разные результаты, где C# значительно медленнее в обоих тестах: 177% для массива и 212% для вектора / списка.

Johan Boulé 17.07.2016 07:24

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

U007D 07.09.2016 23:56

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

Бонусы C / C++ наиболее заметны, если вы придерживаетесь указателей и избегаете Boost, std::vector и других высокоуровневых контейнеров, а также inline для всех возможных небольших функций. По возможности используйте массивы старой школы. Да, вам понадобится больше строк кода, чтобы выполнить то же самое, что и на Java или C#, поскольку вы избегаете высокоуровневых контейнеров. Если вам нужен массив динамического размера, вам просто нужно не забыть связать new T[] с соответствующим оператором delete[] (или использовать std::unique_ptr) - цена за дополнительную скорость заключается в том, что вы должны кодировать более тщательно. Но взамен вы избавляетесь от накладных расходов, связанных с управляемой памятью / сборщиком мусора, которые легко могут составлять 20% или более времени выполнения сильно объектно-ориентированных программ как на Java, так и на .NET, а также от программ с большим количеством управляемых файлов. затраты на индексацию массива памяти. Приложения C++ также могут извлечь выгоду из некоторых изящных переключателей компилятора в определенных конкретных случаях.

Я опытный программист на C, C++, Java и C#. Недавно у меня была редкая возможность реализовать одну и ту же алгоритмическую программу на последних трех языках. В программе было много математических операций и операций с многомерными массивами. Я сильно оптимизировал это на всех 3 языках. Результаты были типичными для того, что я обычно вижу при менее строгих сравнениях: Java была примерно в 1,3 раза быстрее, чем C# (большинство JVM более оптимизированы, чем CLR), а версия с исходным указателем C++ появилась примерно в 2,1 раза быстрее, чем C#. Обратите внимание, что программа на C# использовала только безопасный код - я считаю, что вы могли бы также написать его на C++ перед использованием ключевого слова unsafe.

Чтобы никто не подумал, что я имею что-то против C#, в заключение скажу, что C#, вероятно, мой любимый язык. Это самый логичный, интуитивно понятный и быстрый язык разработки, с которым я когда-либо сталкивался. Все свои прототипы я делаю на C#. У языка C# есть много мелких, тонких преимуществ перед Java (да, я знаю, что Microsoft смогла исправить многие недостатки Java, запоздав в игру и, возможно, скопировав Java). Кто-нибудь тост за класс Java Calendar? Если Microsoft когда-либо приложит реальные усилия для оптимизации CLR и .NET JITter, C# может серьезно взять верх. Я искренне удивлен, что они еще этого не сделали - они сделали так много вещей правильно на языке C#, почему бы не дополнить это серьезной оптимизацией компилятора? Может быть, если мы все будем умолять.

"вам просто нужно не забыть подключить свой new T[] к соответствующему delete[]" – No you don't. There's std::unique_ptr to do that for you.
emlai 29.12.2015 04:11

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

user219279 12.04.2016 09:53

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

Нотч закодировал Minecraft так, чтобы он работал довольно быстро, учитывая объем данных, которыми он манипулирует. Кроме того, он кодировал его в основном в одиночку за сравнительно короткий промежуток времени, что было бы практически невозможно в C++. Однако я согласен с методами оптимизации - если у вас есть дополнительное 10-кратное время разработки, чтобы ваш код работал в два раза быстрее, вероятно, оно того стоит.

Bill K 02.03.2018 02:21

Если не ошибаюсь, шаблоны C# определяются во время выполнения. Это должно быть медленнее, чем шаблоны времени компиляции C++.

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

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

Вердикт:

  • C#: более быстрая разработка, более медленный запуск

  • C++: медленная разработка, более быстрый запуск.

Я собираюсь начать с того, что не согласен с частью принятого (и получившего большое количество голосов) ответа на этот вопрос, заявив:

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

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

  • любые горячие пути в JITter будут конкурировать с вашим кодом за кеширование инструкций и данных в ЦП. Мы знаем, что кеш-память доминирует, когда дело доходит до производительности, и такие родные языки, как C++, по определению не имеют такого типа конкуренции.

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

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

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

Это очень длинная и сложная тема, но я считаю, что для полноты картины стоит упомянуть, что оптимизатор времени выполнения C# превосходен и может выполнять определенные динамические оптимизации во время выполнения, которые просто недоступны для C++ с его временем компиляции ( static) оптимизатор. Даже с этим преимуществом, как правило, остается собственное приложение, но динамический оптимизатор является причиной квалификатора «почти конечно», указанного выше.

-

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

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

Вместо этого я написал немного более идиоматический код C++ и сравнил его с кодом C#, предоставленным @Wiory. В код C++ я внес два основных изменения:

1) использовал vector :: reserve ()

2) сгладил массив 2d до 1d, чтобы добиться лучшей локальности кеша (непрерывный блок)

C# (.NET 4.6.1)

private static void TestArray()
{
    const int rows = 5000;
    const int columns = 9000;
    DateTime t1 = System.DateTime.Now;
    double[][] arr = new double[rows][];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    DateTime t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

    t1 = System.DateTime.Now;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);
}

Время выполнения (релиз): начало: 124 мс, заполнение: 165 мс

C++ 14 (Clang v3.8 / C2)

#include <iostream>
#include <vector>

auto TestSuite::ColMajorArray()
{
    constexpr size_t ROWS = 5000;
    constexpr size_t COLS = 9000;

    auto initStart = std::chrono::steady_clock::now();

    auto arr = std::vector<double>();
    arr.reserve(ROWS * COLS);

    auto initFinish = std::chrono::steady_clock::now();
    auto initTime = std::chrono::duration_cast<std::chrono::microseconds>(initFinish - initStart);

    auto fillStart = std::chrono::steady_clock::now();

    for(auto i = 0, r = 0; r < ROWS; ++r)
    {
        for (auto c = 0; c < COLS; ++c)
        {
            arr[i++] = static_cast<double>(r * c);
        }
    }

    auto fillFinish = std::chrono::steady_clock::now();
    auto fillTime = std::chrono::duration_cast<std::chrono::milliseconds>(fillFinish - fillStart);

    return std::make_pair(initTime, fillTime);
}

Время выполнения (Release): Начало: 398 мкс (да, это микросекунды), заполнение: 152 мс

Общее время выполнения: C#: 289 мс, C++ 152 мс (примерно на 90% быстрее)

Наблюдения

  • Изменение реализации C# на ту же реализацию 1d-массива дал инициализацию: 40 мс, заполнение: 171 мс, итого: 211 мс (C++ все еще был почти На 40% быстрее).

  • Спроектировать и написать «быстрый» код на C++ намного сложнее, чем написать «обычный» код на любом из языков.

  • (Возможно) удивительно легко добиться низкой производительности в C++; мы видели это с неограниченной производительностью векторов. И таких подводных камней немало.

  • Производительность C# просто потрясающая, если учесть все, что происходит во время выполнения. И эту производительность сравнительно легко доступ.

  • Дополнительные анекдотические данные, сравнивающие производительность C++ и C#: https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=gpp&lang2=csharpcore

Суть в том, что C++ дает вам гораздо больше контроля над производительностью. Вы хотите использовать указатель? Ссылка? Стековая память? Куча? Динамический полиморфизм или устранение накладных расходов времени выполнения vtable с помощью статического полиморфизма (через шаблоны / CRTP)? В C++ вы должны ... э-э, добраться до делать все эти (и даже другие) варианты самостоятельно, в идеале, чтобы ваше решение наилучшим образом решало проблему, которую вы решаете.

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

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

U007D 09.03.2017 03:44

@Quonux, почему ты должен так писать? Это люди вроде вас заставляют меня не любить stackoverflow.

Markus Knappen Johansson 21.07.2017 00:03

@MarkusKnappenJohansson У меня был плохой день;), я тоже просто человек, снял свой голос против, но мое мнение по-прежнему актуально. Ой, пожалуйста, не любите ТАК только потому, что есть какие-то "глупые" люди :). Всего хорошего.

Quonux 22.07.2017 20:17

СОВЕРШЕННО НЕПРАВИЛЬНЫЙ ЭТАЛОН. В версии C++ вы просто резервируете часть памяти (а затем удивляетесь, как эта операция занимает микросекунды для выполнения). В версии C# вы создаете 5000 МАССИВОВ (создание экземпляров объектов в памяти). C++ быстрее, чем C# ... но разница далеко не 40% ... сейчас она больше в диапазоне <10%. Ваш пример показывает, что программисты должны придерживаться языка по своему выбору (и из вашего профиля очевидно, что вы карьерный программист на C++). В C# вы можете создать 2D-массив int[,] ... после примера.

nikib3ro 27.12.2017 20:52

Итак, я переделал пример C# на своей машине, чтобы использовать double[,], который ближе к тому, что используется в тесте. Это все еще не идеальное сравнение, поскольку почти все в C# является объектом, который инициализируется в памяти (и там есть накладные расходы). Результаты: инициализация заняла 3 мс, выполнение - 95 мс. Так что теперь я могу заявить, что C# на 40% БЫСТРЕЕ, чем C++. Что явно не так. Может моя машина быстрее, чем @ U007D. Возможно, я забыл установить режим Release (тогда мой код выполняется> 300 мсек). Вывод: скорость компилируемого кода одинакова. Насколько хорошо вы написали код, гораздо важнее.

nikib3ro 27.12.2017 21:04

Насколько я могу судить, код в вашем примере на C++ буквально распределяет память заранее. Реализация PROPER C# просто напишет «List <double> arrs = new List <double> (ROWS * COLS)», которая выделяет память, необходимую для индексации двухмерного массива в одномерном формате (например, то, что вы делали на C++). Нет абсолютно никаких причин выделять двумерный массив и вручную сглаживать его - огромное количество итераций в вашем предварительном тесте является причиной плохой производительности. Я полагаю, что накладные расходы все же будут больше в C#, но не намного.

JDSweetBeat 07.07.2018 04:42

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

Orestis P. 03.10.2018 12:21

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

U007D 17.07.2019 18:46

@JDSweetBeat, возможно, вы пропустили сравнение сопоставимой реализации C#, которую я предоставил. См. Первый пункт в разделе «Наблюдения» выше.

U007D 17.07.2019 18:48

@ U007D Спасибо, что указали на это, я действительно пропустил этот пункт :-)

JDSweetBeat 25.07.2019 05:12

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

Stefan Reich 18.01.2020 17:02

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

Lokanath 29.01.2020 07:41

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

gjvdkamp 19.11.2020 11:58

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

Я ни в коем случае не проводил исчерпывающих сравнений алгоритмической сложности между языками. Я просто использую настройки по умолчанию для каждого из языков. В VB.NET я использую настройки, требующие объявления переменных и т. д. Вот код, который я использую для управляемого C++: (Как видите, этот код довольно прост). Я использую то же самое на других языках в Visual Studio 2013 с .NET 4.6.2.

#include "stdafx.h"

using namespace System;
using namespace System::Diagnostics;

bool EqualMe(String^ first, String^ second)
{
    return first->Equals(second);
}
int main(array<String ^> ^args)
{
    Stopwatch^ sw = gcnew Stopwatch();
    sw->Start();
    for (int i = 0; i < 100000; i++)
    {
        EqualMe(L"one", L"two");
    }
    sw->Stop();
    Console::WriteLine(sw->ElapsedTicks);
    return 0;
}

Есть несколько основных различий между C# и C++ в аспекте производительности:

  • C# основан на GC / heap. Выделение и сам сборщик мусора являются накладными, поскольку нелокальность доступа к памяти
  • Оптимизаторы C++ стали очень хорошими за эти годы. Компиляторы JIT не могут достичь того же уровня, поскольку у них есть только ограниченное время компиляции и они не видят глобальную область видимости.

Кроме того, играет роль и компетентность программиста. Я видел плохой код C++, где классы передавались по значению в качестве аргумента повсюду. Вы действительно можете снизить производительность в C++, если не знаете, что делаете.

Я обнаружил, что в апреле 2020 года я прочитал: https://www.quora.com/Why-is-C-so-slow-compared-to-Python от реального программиста с более чем 15-летним опытом разработки программного обеспечения.

В нем говорится, что C# обычно медленнее, потому что он скомпилирован в Общий промежуточный язык (CIL) вместо машинного кода, такого как C++. Затем CIL проходит через Общеязыковая среда выполнения (CLR), который выводит машинный код. Однако, если вы продолжите выполнение C#, он примет вывод машинного кода и кешировать его, чтобы машинный код был сохранен для следующего выполнения. В общем, C# может быть быстрее, если вы выполняете несколько раз, поскольку он находится в машинном коде после нескольких выполнений.

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

Другие вопросы по теме