2009-09-16 15 views
11

En el proceso de aprendizaje de P/Invoke, me hicieron esta pregunta anterior:diferencias de rendimiento entre P/Invoke y C envolturas ++

How to P/Invoke when pointers are involved

Sin embargo, yo no entiendo muy bien las implicaciones de usar P/Invoke en C# sobre la creación de un contenedor en Managed C++. La creación de la misma DLL usando P/Invoke en C# definitivamente resultó en una interfaz más limpia ya que podría usar DLLImport en un recurso incrustado, pero ¿tendría un mejor desempeño un contenedor administrado de C++ para una DLL nativa, donde yo mismo hago los cálculos?

Respuesta

12

C++ envoltorio debe ser más rápido, echar un vistazo a este MSDN page:

C++ interoperabilidad utiliza el método más rápido posible de cálculo de referencias de datos, mientras que P/Invoke utiliza el método más robusto. Esto significa que C++ Interop (de una manera típica para C++) proporciona un rendimiento óptimo por defecto, y el programador es responsable de atender los casos donde este comportamiento no es seguro o apropiado.

Básicamente, la razón principal es que P/Invoke hace pinning, blitting, comprobación de errores, mientras que la interoperabilidad de C++ simplemente empuja los parámetros en la pila y llama a la función.

Otro punto a recordar es que C++ puede llamar a varias API en una sola llamada, mientras que P/Invoke CADA parámetro pasado por la dirección se inmovilizó y desprendida en cada llamada, copiado y copiado espalda, etc.

+1

Lo he leído antes, pero lo leí en el sentido de que el uso de la interoperabilidad de C++ desde C++, en lugar de utilizar P/Invoke desde C++, es más rápido, lo que habría asumido de todos modos. No trata necesariamente de ir de C# a C++ a DLL en lugar de C# a DLL a través de P/Invoke –

+0

No lo creo, porque Managed C++ sigue siendo un lenguaje administrado (transformado en código IL) llamándolo desde C# no incurrir en una sobrecarga de alto rendimiento –

+0

Aceptado esto ya que esto es más o menos correcto. Lo único que me confunde es dónde se detiene el IL y el código nativo, ya que puedes usar tanto punteros nativos como objetos y objetos administrados mezclados en C++. No está claro en qué punto puede dejar espacio administrado y entrar en el nativo. –

6

Would obtienes un mejor rendimiento? Depende de lo que estás haciendo y cómo lo estás haciendo. En términos generales, es probable que su impacto en el rendimiento provenga de las transiciones gestionadas/no gestionadas y cuanto más recorte, mejor. Idealmente, su interfaz con el código no administrado debe ser gruesa y no ser parlante.

Digamos que tiene un código no administrado que tiene una colección de unos pocos miles de objetos. Ya que podría exponer una API como esta para código administrado:

int GetFooCount(); 
IntPtr GetFoo(int n); 
void ReleaseFoo(IntPtr p); 

y eso es todo muy bien, hasta que comience a usarlo en C# como esto:

int total = API.GetFooCount(); 
IntPtr[] objects = new IntPtr[total]; 
for (int i=0; i < total; i++) { 
    objects[i] = GetFoo(i); 
} 
// and later: 
foreach (IntPtr p in objects) { ReleaseFoo(p); } 

que por == total de 1000, se ser 4002 transiciones gestionadas/no gestionadas. Si en su lugar tiene esto:

int GetFooCount(); 
void GetFoos(IntPtr[] arr, int start, int count); 
void ReleaseFoos(IntPtr arr, int start, int count); 

entonces puede hacer el mismo trabajo con 6 transiciones. ¿Cuál crees que funcionará mejor?

Por supuesto, la siguiente pregunta importante que debe hacerse es "¿vale la pena el rendimiento?" así que recuerda medir primero.

Una cosa que también debes tener en cuenta es que le pueden pasar cosas divertidas a STL cuando trabajas con C++ administrado. Tengo un código de biblioteca no administrado que usa STL. Mi experiencia fue que si alguna vez toqué alguno de los tipos de STL en C++ administrado, TODOS se convirtieron en implementaciones administradas. El resultado final de esto fue que el código de bajo nivel estaba haciendo transiciones administradas/no administradas al iterar las listas. Yikes. Lo resolví al nunca exponer los tipos de STL a C++ administrado.

En nuestra experiencia, es mucho mejor (si es posible) ir a C# -> biblioteca C++ wrapper-> estática administrada, si tienes la posibilidad de hacerlo.

Cuestiones relacionadas