Udostępnij przez


Zagadnienia dotyczące wydajności związane z międzyoperacyjnością (C++)

Ten temat zawiera wskazówki dotyczące zmniejszenia wpływu przejścia międzyoperacyjności zarządzanych/niezarządzanych na wydajność czasu wykonywania.

Język Visual C++ obsługuje te same mechanizmy współdziałania co inne języki platformy .NET, takie jak Visual Basic i C# (P/Invoke), ale zapewnia również obsługę międzyoperacyjności specyficzną dla języka Visual C++ (międzyoperacyjność języka C++). W przypadku aplikacji o krytycznym znaczeniu dla wydajności ważne jest, aby zrozumieć wpływ na wydajność każdej techniki międzyoperacyjnej.

Niezależnie od używanej techniki międzyoperacyjnej specjalne sekwencje przejścia nazywane thunks są wymagane za każdym razem, gdy funkcja zarządzana wywołuje funkcję niezarządzaną i odwrotnie. Te thunks są wstawiane automatycznie przez kompilator języka Microsoft C++, ale należy pamiętać, że skumulowanie te przejścia mogą być kosztowne pod względem wydajności.

Zmniejszanie przejść

Jednym ze sposobów uniknięcia lub zmniejszenia kosztów międzyoperacyjności thunks jest refaktoryzacja interfejsów zaangażowanych w celu zminimalizowania zarządzanych/niezarządzanych przejść. Znaczne ulepszenia wydajności można wprowadzić przez ukierunkowanie interfejsów czatty, które obejmują częste wywołania w granicach zarządzanych/niezarządzanych. Funkcja zarządzana, która wywołuje funkcję niezarządzaną w ciasnej pętli, na przykład, jest dobrym kandydatem do refaktoryzacji. Jeśli pętla zostanie przeniesiona do niezarządzanej strony lub jeśli zostanie utworzona zarządzana alternatywa dla niezarządzanego wywołania (być może dane są kolejkowane po stronie zarządzanej, a następnie marshaling jej do niezarządzanego interfejsu API jednocześnie po pętli), można znacznie zmniejszyć liczbę przejść.

Międzyoperacyjności P/Invoke a C++

W przypadku języków platformy .NET, takich jak Visual Basic i C#, zalecana metoda współdziałania ze składnikami natywnymi to P/Invoke. Ponieważ funkcja P/Invoke jest obsługiwana przez program .NET Framework, program Visual C++ obsługuje go również, ale program Visual C++ zapewnia również własną obsługę współdziałania, nazywaną międzyoperacyjnością języka C++. Interop języka C++ jest preferowany przez P/Invoke, ponieważ P/Invoke nie jest bezpieczny pod kątem typu. W związku z tym błędy są zgłaszane głównie w czasie wykonywania, ale międzyoperacyjność języka C++ ma również zalety wydajności w stosunku do P/Invoke.

Obie techniki wymagają kilku rzeczy, gdy funkcja zarządzana wywołuje funkcję niezarządzaną:

  • Argumenty wywołań funkcji są marshalowane z clR do typów natywnych.

  • Jest wykonywany zarządzany do niezarządzany thunk.

  • Funkcja niezarządzana jest wywoływana (przy użyciu natywnych wersji argumentów).

  • Jest wykonywany niezarządzany do zarządzania thunk.

  • Typ zwracany i wszystkie argumenty "out" lub "in", out" są marshalowane z natywnych do typów CLR.

Zarządzane/niezarządzane thunks są niezbędne do współdziałania w ogóle, ale wymagane marshaling danych zależy od zaangażowanych typów danych, sygnatury funkcji i sposobu użycia danych.

Marshaling danych wykonywany przez międzyoperacyjności języka C++ jest najprostszą możliwą formą: parametry są po prostu kopiowane przez zarządzaną/niezarządzaną granicę w sposób bitowy; w ogóle nie jest wykonywana żadna transformacja. W przypadku funkcji P/Invoke jest to prawda tylko wtedy, gdy wszystkie parametry są prostymi typami blittable. W przeciwnym razie funkcja P/Invoke wykonuje bardzo niezawodne kroki, aby przekonwertować każdy zarządzany parametr na odpowiedni typ natywny i odwrotnie, jeśli argumenty są oznaczone jako "out" lub "in,out".

Innymi słowy, międzyoperacyjność języka C++ używa najszybszej możliwej metody marshalingu danych, podczas gdy P/Invoke używa najbardziej niezawodnej metody. Oznacza to, że międzyoperacyjność języka C++ (w sposób typowy dla języka C++) zapewnia optymalną wydajność domyślnie, a programista jest odpowiedzialny za rozwiązywanie przypadków, w których takie zachowanie nie jest bezpieczne lub odpowiednie.

Dlatego międzyoperacyjność języka C++ wymaga jawnego podania marshalingu danych, ale zaletą jest to, że programista może zdecydować, co jest odpowiednie, biorąc pod uwagę charakter danych i sposób ich użycia. Ponadto, mimo że zachowanie funkcji marshalingu danych P/Invoke można modyfikować na poziomie dostosowanym do danego stopnia, interop języka C++ umożliwia dostosowywanie marshalingu danych na podstawie wywołań. Nie jest to możliwe w przypadku operacji P/Invoke.

Aby uzyskać więcej informacji na temat międzyoperacyjności języka C++, zobacz Using C++ Interop (Implicit PInvoke)( Using C++ Interop (Implicit PInvoke) (Korzystanie z międzyoperacyjności języka C++ (niejawna funkcja PInvoke).

Zobacz też

Zestawy mieszane (natywne i zarządzane)