#c #c -cli
#c #c -cli
Вопрос:
Я хочу делегировать аудио вычисления уровню C , но обрабатывать и редактировать аудиоконтент через графический интерфейс WPF.
Я кратко ознакомился с C / CLI, и я хотел бы знать:
- должен ли я использовать C / CLI в качестве промежуточного уровня между C # GUI и C audio management
- или я должен просто поместить свой код в C / CLI и ожидать, что он будет скомпилирован таким же образом, таким образом, максимально эффективно.
РЕДАКТИРОВАТЬ: поскольку может начаться пламенная война. Это ссылка, ведущая к игре benchmarks, в которой четко указано, что C / C выигрывают в скорости. Я спрашиваю: должен ли я писать свой C в C Dll или в C CLI assembly.
Комментарии:
1. Проблема с C / CLI заключается в слабых возможностях оптимизации. Напишите «вычислительную» библиотеку на чистом C в виде статической библиотеки, затем предоставьте ее как интерфейс .NET с оболочкой C / CLI (это даст вам уникальную повторно используемую DLL) и используйте C # (или любой другой язык .NET) для остальной части вашего проекта. Для этого вам понадобятся 3 проекта Visual Studio (по одному для каждого языка). Я всегда делаю это и получаю лучшее из обоих миров.
2. @Alexandre: Это проблема с MSIL (и даже там компилятор C / CLI генерирует более эффективный код, чем компилятор C #), а не C / CLI, который поддерживает все стандартные конструкции C и может генерировать собственный код из них.
3. @Ben Voigt: Я не знаю ни одного компилятора C / CLI для чего-либо другого, кроме MSIL.
4. @Alexandre C.: Две вещи. 1. MSIL больше не существует; теперь он называется CIL 😉 2. Компилятор C / CLI генерирует собственный код . Единственными классами, которые будут управляться, являются те, которые вы указали ему сделать управляемыми (
ref class
). Это одна из причин, по которой вы не можете просто взять C и скомпилировать как C / CLI и ожидать, что код будет работать в средах с низким уровнем доверия, таких как Silverlight или телефон. (Вам пришлось бы использовать/clr:safe
для этого, что по сути требует, чтобы вы все переписали)5. @BillyONeal: Компилятор не компилирует только управляемые типы (
ref class
) в CIL. Стандартный код C будет скомпилирован в CIL, если он появится внутри файла, скомпилированного с/clr
, а не внутри#pragma unmanaged
./clr:pure
отлично работает с большинством стандартного кода C .
Ответ №1:
В C / CLI управляемые типы ( ref class
например) и их члены компилируются в MSIL. Это означает отсутствие использования SIMD и гораздо меньшую оптимизацию (по крайней мере, в текущей версии .NET, и причины, приведенные Microsoft, не изменятся в ближайшее время, хотя они могли бы изменить свою оценку компромиссов).
Собственные типы, с другой стороны, могут быть скомпилированы либо в MSIL, либо в машинный код. Хотя Visual C не обладает лучшим оптимизатором C в мире, он очень, очень хорош. Поэтому моей рекомендацией было бы скомпилировать машинный код. Visual C будет использовать взаимодействие C при вызове между управляемым и собственным кодом, что очень эффективно (это одна и та же internalcall
технология, используемая для всех .Встроенные функции NET, такие как конкатенация строк).
Чтобы это произошло, вы можете либо поместить свой критичный по времени код в отдельный объектный файл (не отдельную DLL!, пусть компоновщик объединяет управляемый и неуправляемый код в сборку «смешанного режима»), скомпилированный без /clr
, либо заключить его в скобки с #pragma managed(push, off)
… #pragma managed(pop)
. В любом случае вы получите максимальную оптимизацию и сможете использовать встроенные функции SIMD для очень быстрого кода.
Комментарии:
1. Наконец, я выбираю ваш ответ по выбору. Спасибо за трюк с управлением /clr и #pragma: приятно это знать. Но, честно говоря, я склонен предпочитать родную C Dll. (Старые привычки 😉 )
2. @Stephane: Просто имейте в виду, что вызов собственной библиотеки DLL через p / invoke намного медленнее, чем использование взаимодействия C внутри библиотеки DLL смешанного режима. Если вы внимательно относитесь к используемым типам (например, избегайте строк ANSI, поскольку они всегда будут преобразованы в / из . Представление NET в Юникоде) вы можете минимизировать эти затраты,
3. @Ben, я больше думал о статической привязке к myNativeDll.lib в myCliIAssembly… Спасибо, что вы знаете о хитрости ansi / unicode. Но, к счастью, я, вероятно, буду вводить / выводить только тонны массивов с плавающей запятой / double с некоторыми целочисленными идентификаторами. (Однако я буду помнить о проблеме преобразования строк … если когда-либо были нужны строки …).
4. @Stephane:
mynativedll.lib
звучит больше как библиотека импорта, чем статическая библиотека объектов. Тем не менее, если вы вызываете эти функции из C / CLI, вы получите эффективное взаимодействие C / CLI.5. @Stephane: Библиотека импорта — это особый вид статической библиотеки, которая имеет заполнители для функций DLL. Загрузчик операционной системы заменяет их фактическим адресом загрузки DLL во время выполнения. В библиотеке импорта нет фактического кода, и когда вы связываетесь с ней, ваше приложение бесполезно без наличия DLL. «статическое связывание» означает, что код библиотеки включен в ваше приложение, ваш файл .exe содержит все, что ему нужно для независимого запуска (но обратите внимание, что вы можете использовать смесь, импортируя DLL для одной библиотеки и статически связывая другую).
Ответ №2:
Объединение уровня C / CLI — это процесс сортировки, при котором управляемое состояние преобразуется в примитивные типы для маршалирования на неуправляемый уровень, обрабатывается, а затем маршалируется обратно. В зависимости от вашего алгоритма (и прагматики для «упаковки» этого переходного уровня), лучше всего сохранять сортировку как можно более ограниченной (маленькой).
Итак, это зависит от проблемы: простейшей проблемой был бы интерфейс, который отправляет немного примитивных данных через уровень C / CLI, обрабатывает долгое время, а затем отправляет немного данных обратно (например, минимальные накладные расходы на маршалинг). Если ваш алгоритм требует более обширного взаимодействия на уровне C / CLI, это становится намного сложнее.
Преимущество «Всего C #» или «Всего управляемого» заключается в (1) пропуске этого уровня сортировки (который является накладным, а иногда и утомительным в зависимости от работы), и (2) оптимизации во время выполнения, которые .NET engine может создавать для конкретного компьютера, на котором выполняется код (чего вы не можете иметь ни с native C / C , ни с неуправляемым кодом).
Я согласен с другими комментариями в этой теме, что вы должны «протестировать» это в своих сценариях. «Большой» уровень C / CLI с чувствительным к производительности переходом выполнить очень сложно из-за «упаковки / распаковки», которая (автоматически) возникает, когда вы продолжаете переключаться между управляемым / неуправляемым.
Наконец, конечная разница в производительности между гибридным дизайном «управляемый / неуправляемый» и дизайном «полностью управляемый» связана с компромиссами между: Может ли .NET engine выполняет машинную оптимизацию .ЧИСТЫЙ код (например, использующий преимущества машинных потоков / ядер / регистров), больший, чем «чистый собственный» код (который связан с сборкой в смешанном режиме), способен быстро обрабатываться в обход .NET engine (который является интерпретатором)?
Действительно, хорошо написанный собственный код может «обнаруживать» потоки процессора, но обычно не может обнаруживать специфичные для машины регистры (если только он не скомпилирован для этой целевой платформы). В отличие от этого, собственный код не требует «накладных расходов» на прохождение .NET runtime, которая является просто виртуальной машиной (которая может быть «ускорена» за счет своевременной компиляции некоторой логики для ее конкретного базового оборудования).
Сложная проблема. Извините. ИМХО, просто нет простых ответов на проблемы такого типа, если ваша проблема связана с «чувствительностью к производительности».
Комментарии:
1. @charley, я поэкспериментирую с обоими и приму решение позже. Я не был осведомлен о процессе сортировки.
2. Как вы думаете, почему c и c нельзя написать для оптимизации во время выполнения? или для обнаружения функций процессора, таких как регистры или SSE, во время выполнения? Это делается постоянно. .NET — это не волшебство. Просто любопытно.
3. Я согласен, что C / C можно написать для значительной оптимизации во время выполнения, например, для вычисления «оптимального» количества потоков на основе выполняемого в данный момент оборудования. Однако эта эвристическая логика использования аппаратных преимуществ является всего лишь логикой виртуальной машины. Если вы напишете один, вы сможете это сделать. В противном случае, это цель . Виртуальная машина NET. —Согласен, .NET — это не волшебство, я нахожу C / C намного быстрее / проще / мощнее. Но я бы рассматривал C # / .NET везде, где в противном случае рассматривал бы Python.
4. Итак, есть оптимизации, которые . NET теоретически мог бы создать для конкретного компьютера, но в настоящее время не существует ни одной версии .NET, которая действительно это делает.
5. @charley: Оптимизация во время выполнения может быть очень эффективной и совсем не походить на виртуальную машину. Часто это так же просто, как тестирование типа процессора и присвоение указателя функции одной из множества реализаций, где каждая реализация была оптимизирована с использованием различных настроек компилятора. Даже в крайнем случае (ATLAS, автоматически настраиваемая система линейной алгебры), нет ничего похожего на реализацию виртуальной машины.
Ответ №3:
Я рекомендую вам взглянуть на эту статью. Кроме того, при попытке решить, на каком языке лучше всего писать ваш код, вы должны (всегда) выполнить небольшой тест для вашего случая, чтобы увидеть, есть ли какие-либо различия для конкретного случая, который у вас есть.
Комментарии:
1. согласно этой статье, управляемый код быстрее, чем неуправляемый …хм
2. нет — согласно этой статье, результат зависит от обстоятельств. Это может быть медленнее, но также может быть и быстрее.
Ответ №4:
Из моего собственного тестирования, которое я провел на тему, C # быстрее, чем родной C для алгоритмов. Единственным недостатком является то, что в Интернете меньше алгоритмов для C #, чем для C .
Комментарии:
1. когда вы говорите «родной», это C / CLI или чистый c ?
2. Вы, вероятно, просто пишете плохой C , например, передаете все по значению. Или вы тестировали отладочные сборки. Распространенные ошибки для разработчиков C #.
3. В некоторых случаях хороший C # может быть быстрее хорошего C , особенно если выделение памяти является узким местом программы на C (и вы не утруждаете себя пользовательскими распределителями). Но это не общий случай.