Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом разделе представлены рекомендации по уменьшению воздействия переходов между управляемой и неуправляемой средами на производительность в рантайме.
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++ Interop. Взаимодействие C++ предпочтительнее по сравнению с P/Invoke, так как P/Invoke не является типобезопасным. В результате ошибки в основном сообщаются во время выполнения, но C++ Interop (взаимодействие C++) также имеет преимущества в производительности по сравнению с P/Invoke.
Оба метода требуют выполнения нескольких действий, когда управляемая функция вызывает неуправляемую функцию:
Аргументы вызова функции маршалируются из среды CLR в нативные типы.
Выполняется переход от управляемого к неуправляемому thunk.
Неуправляемая функция вызывается (используя собственные версии аргументов).
Выполняется переход от неуправляемой к управляемой thunk.
Возвращаемый тип и любые аргументы "out" или "in,out" маршалируются из собственных типов в типы среды CLR.
Управляемые или неуправляемые thunks необходимы для взаимодействия между компонентами, но маршалирование данных, которое требуется, зависит от типов данных, задействованных в процессе, сигнатуры функции и способа использования данных.
Маршалинг данных, выполняемый взаимодействием C++, является самой простой формой: параметры просто копируются через управляемую или неуправляемую границу по битовой форме; преобразование не выполняется вообще. Для P/Invoke это верно только в том случае, если все параметры являются простыми, блитт-перемещаемыми типами. В противном случае P/Invoke выполняет очень надежные процедуры для преобразования каждого управляемого параметра в соответствующий собственный тип и наоборот, если аргументы помечены как out; in,out.
Другими словами, C++ Interop использует самый быстрый метод маршалинга данных, в то время как P/Invoke использует самый надежный метод. Это означает, что взаимодействие C++ в манере, типичной для C++, обеспечивает оптимальную производительность по умолчанию, и программист несет ответственность за случаи, когда это поведение небезопасно или неуместно.
Для взаимодействия с C++ Interop требуется явное предоставление маршалинга данных, но преимущество в том, что программист может самостоятельно определить, что является подходящим, учитывая характер данных и то, как они будут использоваться. Кроме того, хотя поведение маршалинга данных P/Invoke можно в какой-то степени изменять, взаимодействие C++ позволяет настраивать маршалинг данных для каждого вызова отдельно. Это невозможно с помощью P/Invoke.
Дополнительные сведения о взаимодействии C++ см. в разделе Использование Interop C++ (Implicit PInvoke).