Вопросы производительности взаимодействия (C++)

В этом разделе приведены рекомендации по сокращению влияния переходов управляемого или неуправляемого взаимодействия на производительность во время выполнения.

Visual C++ поддерживает те же механизмы взаимодействия, что и другие языки .NET, такие как Visual Basic и C# (P/Invoke), но также обеспечивает поддержку взаимодействия, относящуюся к Visual C++ (взаимодействие C++). Для критически важных для производительности приложений важно понимать последствия производительности каждого метода взаимодействия.

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

Сокращение переходов

Одним из способов предотвращения или снижения затрат на взаимодействие является рефакторинг интерфейсов, участвующих в минимизации управляемых или неуправляемых переходов. Драматические улучшения производительности можно сделать путем целевых интерфейсов чата, которые являются теми, которые включали частые вызовы через управляемую или неуправляемую границу. Управляемая функция, которая вызывает неуправляемую функцию в жестком цикле, например, является хорошим кандидатом на рефакторинг. Если цикл перемещается на неуправляемую сторону или создается управляемая альтернатива неуправляемой вызову (возможно, данные очереди на управляемой стороне, а затем маршалинг его в неуправляемый API одновременно после цикла), количество переходов может быть значительно сокращено.

P/Invoke vs. C++ Interop

Для языков .NET, таких как Visual Basic и C#, предписанный метод взаимодействия с собственными компонентами — P/Invoke. Так как P/Invoke поддерживается платформа .NET Framework, Visual C++ также поддерживает его, но Visual C++ также предоставляет собственную поддержку взаимодействия, которая называется взаимодействием C++ . Взаимодействие C++ предпочтительнее по сравнению с P/Invoke, так как P/Invoke не является типобезопасным. В результате ошибки в основном сообщаются во время выполнения, но взаимодействие C++ также имеет преимущества производительности по сравнению с P/Invoke.

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

  • Аргументы вызова функции маршалируются из среды CLR в собственные типы.

  • Выполняется управляемый к неуправляемой thunk.

  • Неуправляемая функция вызывается (используя собственные версии аргументов).

  • Выполняется неуправляемая и управляемая thunk.

  • Возвращаемый тип и любые аргументы out или "in", out маршалируются из собственных типов среды CLR.

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

Маршалинг данных, выполняемый взаимодействием C++, является самой простой формой: параметры просто копируются через управляемую или неуправляемую границу по битовой форме; преобразование не выполняется вообще. Для P/Invoke это значение имеет значение true, только если все параметры являются простыми, врезными типами. В противном случае P/Invoke выполняет очень надежные шаги для преобразования каждого управляемого параметра в соответствующий собственный тип, и наоборот, если аргументы помечены как out или in,out.

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

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

Дополнительные сведения о взаимодействиях C++ см. в разделе "Использование взаимодействия C++ (неявное PInvoke)".

См. также

Смешанные (собственные и управляемые) сборки