Pregunta

En el proceso de aprendizaje de P / Invoke, hice esta pregunta anterior:

  

Cómo P / Invocar cuando los punteros están involucrados

Sin embargo, no entiendo 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 envoltorio Managed C ++ para una DLL nativa, donde hago la clasificación?

¿Fue útil?

Solución

El

contenedor C ++ debería ser más rápido, eche un vistazo a esta página MSDN :

  

C ++ Interop usa el método más rápido posible de cálculo de datos, mientras que P / Invoke usa el método más robusto. Esto significa que la interoperabilidad de C ++ (de manera típica para C ++) proporciona un rendimiento óptimo de forma predeterminada, y el programador es responsable de abordar los casos en los que este comportamiento no es seguro o apropiado.

Así que, básicamente, la razón principal es que P / Invoke realiza la fijación, el borrado, la 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 para recordar es que C ++ puede llamar a varias API en una sola llamada, mientras que P / Invocar CADA parámetro pasado por dirección se fija y desancla en CADA llamada, copiada y copiado de vuelta, etc.

Otros consejos

¿Conseguirías un mejor rendimiento? Depende de lo que estés haciendo y de cómo lo estés haciendo. En términos generales, lo más probable es que su éxito en el rendimiento provenga de hacer transiciones administradas / no administradas y cuantas más se puedan eliminar, mejor. Idealmente, su interfaz con el código no administrado debe ser fornido y no hablador.

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

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

y eso está muy bien, hasta que comiences a usarlo en C # así:

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 para un total == 1000, serán 4002 transiciones administradas / no administradas. Si en cambio tienes esto:

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

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

Por supuesto, la siguiente pregunta importante es "¿Vale la pena esta ganancia de rendimiento?" así que recuerda medir primero.

Una cosa que debe tener en cuenta también es que pueden pasar cosas divertidas a STL cuando trabaja con C ++ administrado. Tengo un código de biblioteca no administrado que utiliza STL. Mi experiencia fue que si alguna vez tocaba alguno de los tipos de STL en C ++ administrado, TODOS se convertían en implementaciones administradas. El resultado final de esto fue que el código de bajo nivel estaba haciendo transiciones administradas / no administradas mientras iteraba las listas. Yikes Resolví esto al nunca exponer los tipos de STL a C ++ administrado.

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top