Dela via


Prestandaöverväganden för Interop (C++)

Det här avsnittet innehåller riktlinjer för att minska effekten av hanterade/ohanterade interopövergångar på körningsprestanda.

Visual C++ stöder samma samverkansmekanismer som andra .NET-språk som Visual Basic och C# (P/Invoke), men det ger också interop-stöd som är specifikt för Visual C++ (C++ interop). För prestandakritiska program är det viktigt att förstå prestandakonsekvenserna för varje interop-teknik.

Oavsett vilken interopsteknik som används krävs särskilda övergångssekvenser, så kallade thunks, varje gång en hanterad funktion anropar en ohanterad funktion och vice versa. Dessa thunks infogas automatiskt av Microsoft C++-kompilatorn, men det är viktigt att komma ihåg att dessa övergångar kumulativt kan vara dyra när det gäller prestanda.

Minska övergångar

Ett sätt att undvika eller minska kostnaden för interop-thunks är att omstrukturera de gränssnitt som ingår för att minimera hanterade/ohanterade övergångar. Dramatiska prestandaförbättringar kan göras genom att rikta in sig på chattiga gränssnitt, som är de som involverade frekventa anrop över den hanterade/ohanterade gränsen. En hanterad funktion som anropar en ohanterad funktion i en snäv slinga är till exempel en bra kandidat för refaktorisering. Om själva loopen flyttas till den ohanterade sidan, eller om ett hanterat alternativ till det ohanterade anropet skapas (möjligen genom att köa data på den hanterade sidan och sedan överföra det till det ohanterade API:et på en gång efter loopen), kan antalet övergångar minskas avsevärt.

P/Invoke jämfört med C++ Interop

För .NET-språk, till exempel Visual Basic och C#, är den föreskrivna metoden för samverkan med inbyggda komponenter P/Invoke. Eftersom P/Invoke stöds av .NET Framework stöder Visual C++ det också, men Visual C++ tillhandahåller också ett eget samverkansstöd, som kallas C++ Interop. C++ Interop föredras framför P/Invoke eftersom P/Invoke inte är typsäkert. Därför rapporteras fel främst vid körning, men C++ Interop har också prestandafördelar jämfört med P/Invoke.

Båda teknikerna kräver flera saker när en hanterad funktion anropar en ohanterad funktion:

  • Argumenten för funktionsanrop konverteras från CLR till interna typer.

  • En hanterad till ohanterad thunk körs.

  • Den ohanterade funktionen anropas (med hjälp av de inhemska versionerna av argumenten).

  • En ohanterad till hanterad thunk körs.

  • Returtypen och argumenten "out" eller "in,out" konverteras från inbyggda till CLR-typer.

De hanterade/ohanterade thunks är nödvändiga för att interop ska fungera över huvud taget, men den datahantering som krävs beror på de datatyper som ingår, funktionssignaturen och hur data kommer att användas.

Datamarseringen som utförs av C++ Interop är det enklaste möjliga formatet: parametrarna kopieras helt enkelt över den hanterade/ohanterade gränsen på ett bitvis sätt. ingen transformering utförs alls. För P/Invoke gäller detta bara om alla parametrar är enkla, blittable-typer. Annars utför P/Invoke mycket robusta steg för att konvertera varje hanterad parameter till en lämplig intern typ och vice versa om argumenten är markerade som "out" eller "in,out".

Med andra ord använder C++ Interop den snabbaste möjliga metoden för datamarsering, medan P/Invoke använder den mest robusta metoden. Det innebär att C++ Interop (på ett sätt som är typiskt för C++) ger optimala prestanda som standard, och programmeraren ansvarar för att hantera fall där det här beteendet inte är säkert eller lämpligt.

C++ Interop kräver därför att datamarhering måste tillhandahållas uttryckligen, men fördelen är att programmeraren är fri att bestämma vad som är lämpligt, med tanke på datatypen och hur de ska användas. Även om beteendet för P/Invoke-datamarshaling kan ändras i viss utsträckning, tillåter C++ Interop att datamarshaling anpassas för varje anrop. Detta är inte möjligt med P/Invoke.

Mer information om C++ Interop finns i Using C++ Interop (Implicit PInvoke).

Se även

Blandade (ursprungliga och hanterade) samlingar