Производительность Managed C ++ против UnManaged / native C ++ - PullRequest
9 голосов
/ 10 июня 2010

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

Неуправляемый C ++ быстрее, чем управляемый C ++? а почему?

Управляемый C ++ работает с CLR вместо ОС, а CLR занимается управлением памятью, что упрощает код и, вероятно, также более эффективно, чем код, написанный «программистом» в неуправляемом C ++? или есть какая-то другая причина? При использовании управляемого, как тогда можно избежать динамического выделения памяти, что приводит к снижению производительности, если все это прозрачно для программиста и обрабатывается CLR?

Итак, возвращаясь к моему вопросу, является ли управляемый C ++ более эффективным с точки зрения скорости, чем неуправляемый C ++ и почему?

Ответы [ 8 ]

8 голосов
/ 10 июня 2010

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

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

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

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

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

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

3 голосов
/ 10 июня 2010

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

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

Я несколько обеспокоен сотнями событий каждую миллисекунду . Это очень много. Удастся ли вам выполнить ожидаемую обработку на любом языке?

Как разработчик C ++ для высокопроизводительных систем, я склонен доверять своей способности профилировать и оптимизировать испускаемый код. Это сказал; Существуют очень высокопроизводительные приложения .NET, в которых разработчик приложил большие усилия, чтобы не выполнять динамическое выделение памяти внутри критических циклов - в основном за счет использования выделенных пулов объектов, созданных заранее.

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

2 голосов
/ 23 января 2012

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

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

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

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

2 голосов
/ 10 июня 2010

Все зависит от ситуации.

Вещи, которые делают неуправляемый код быстрее / медленнее управляемого кода:

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

Вещи, которые делают управляемый код быстрее / неуправляемый код медленнее:

  • , поскольку код преобразуется в машинный код непосредственно перед его использованием, управляемый код можно оптимизировать для реального процессора(с неуправляемым кодом вы должны ориентироваться на «минимально поддерживаемый» процессор).

И, вероятно, есть еще много причин.

0 голосов
/ 20 июля 2011

Писать быстрый код, это всегда боль. Основная проблема, которую можно оптимизировать только для одной платформы. Это действительно относится к консоли, встроенной или другой платформе, где аппаратное обеспечение всегда одинаково. В реальном мире ПК это не так. Разное ядро, разное иструкство и т. Д. ... превращают это в кошмар. Это главная проблема, imho, которая действительно делает разницу между кодом man / unam. Мужчина. код может быть оптимистично оптимизируемым для новой платформы при его запуске. Код Unman нет, написано в камне.

0 голосов
/ 24 ноября 2010

Во-первых, ваше утверждение «обрабатывает сотни событий каждую миллисекунду».звучит довольно нереально.Если у вас нет специально разработанного модуля часов в компьютере, я не думаю, что вы можете достичь цели с помощью обычного ПК (типичное разрешение составляет около 10 миллисекунд).Во-вторых, Native C ++ намного лучше с точки зрения производительности.Существует много возможностей оптимизации C ++ для ускорения, в то время как в управляемом коде это невозможно.Также имейте в виду, что сборка мусора в управляемом коде делает производительность непредсказуемой - когда GC запускает весь процесс, он зависает.Как только вы столкнетесь с проблемой, решение станет более болезненным, и теперь все «хорошие стили», предлагаемые управляемым кодом, исчезнут.

Что касается способности оптимизировать управление процессором под ЦП, то это правда, но вы также можете воспользоваться преимуществами функций ЦП (SSE2, MMX и т. Д.) В родном C ++.Исходя из моего опыта, прирост производительности незначителен.

0 голосов
/ 10 июня 2010

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

Это улучшение по сравнению с неуправляемым кодом, где встраивание должно быть «угадано» заранее, а чрезмерное встраивание вредно, потому что это приводит к увеличению размера кода и вызывает проблемы локальности, которые вызывают (очень дорого) L2 / L1кеш отсутствует.Эта информация просто недоступна для статического анализа, поэтому она возможна только в среде JIT.Есть хорошая корзина возможных побед от анализа времени выполнения, таких как оптимизированное разматывание цикла и т. Д.

Я не утверждаю, что .NET JIT'er настолько умный, насколько это возможно, но я знаю, что слышало функциях глобального анализа, и я знаю, что в Hewlett-Packard и других компаниях было проведено много исследований в области анализа времени выполнения.

0 голосов
/ 10 июня 2010

Разве C ++ / CLI не является полуинтерпретируемым языком, как Java?

Кроме того, разве кто-то вчера опубликовал исследование, которое показало, что системы GC всегда работают медленнее, чем не GC?

...