2011-03-21 20 views
16

Entiendo que el código no seguro es más apropiado para acceder a cosas como la API de Windows y hacer fundidos de tipo no seguro que escribir código de rendimiento, pero me gustaría preguntarle si alguna vez ha notado una mejora significativa en el rendimiento aplicaciones del mundo real al usarlo en comparación con el código C# seguro.Verdadero rendimiento de código inseguro

+0

P/Invocar no es lo mismo que 'inseguro' ... No estoy seguro de que el razonamiento siga ... Además: ¿has medido para ver si estás haciendo algo útil aquí? –

+1

Ni seguro ni inseguro se supone que es más eficaz de facto. El rendimiento total depende de los algoritmos que haya implementado en su código. – zerkms

+2

No estoy usando un código inseguro en este momento. Solo trato de entender si vale la pena cambiar partes críticas del código a código inseguro. – Miguel

Respuesta

13

Un buen ejemplo es la manipulación de imágenes. Modificar los Píxeles mediante el uso de un puntero a sus bytes (que requiere un código inseguro) es bastante más rápido.

Ejemplo: http://www.gutgames.com/post/Using-Unsafe-Code-for-Faster-Image-Manipulation.aspx

Dicho esto, para la mayoría de los escenarios, la diferencia podría no ser tan notable. Por lo tanto, antes de usar un código no seguro, perfile su aplicación para ver dónde están los cuellos de botella de rendimiento y pruebe si el código inseguro es realmente la solución para hacerlo más rápido.

+5

La manipulación segura de imágenes también puede ser bastante rápida. Especialmente si su algoritmo puede escribirse para eliminar cheques de límites. Solo uso el código no seguro para copiar los datos del mapa de bits en una matriz y viceversa. Y si usas un 'byte []' incluso puedes evitar eso y solo usar las funciones 'Marshal'. – CodesInChaos

+1

@ Botz3000: Es un enlace excelente (esperando leer el resto del sitio) pero la conclusión es incorrecta. El uso de 'GetPixel' y' SetPixel' _is_ es realmente lento, pero el uso de 'int []' es más o menos tan rápido que usar punteros sin los inconvenientes. –

+0

@CodeInChaos: Tengo que estar de acuerdo. La conclusión a la que llegué es que la única área que se beneficia es copiar los datos del mapa de bits. Sin embargo, aún no he probado usar 'Marshal'. –

13

Como se indicó en otras publicaciones, usted puede usar código inseguro en contextos muy especializados para obtener un rendimiento significativo en la mejora. Uno de esos escenarios se itera sobre las matrices de tipos de valores. El uso de la aritmética de punteros inseguro es mucho más rápido que el patrón habitual de for-loop/indexador ..

struct Foo 
{ 
    int a = 1; 
    int b = 2; 
    int c = 0; 
} 

Foo[] fooArray = new Foo[100000]; 

fixed (Foo* foo = fooArray) // foo now points to the first element in the array... 
{ 
    var remaining = fooArray.length; 
    while (remaining-- > 0) 
    { 
     foo->c = foo->a + foo->b; 
     foo++; // foo now points to the next element in the array... 
    } 
} 

El beneficio principal aquí es que hemos reducido índice de matriz a cabo la comprobación del todo ..

Si bien es muy En rendimiento, este tipo de código es difícil de manejar, puede ser bastante peligroso (inseguro) y rompe algunas pautas fundamentales (estructura mutable). Pero sin duda hay escenarios donde esto es apropiado ...

+4

Otro gran inconveniente de este tipo de código es que no una gran proporción de programadores de C# lo entienden o sus implicaciones. Si está trabajando en equipo, adopte el principio KISS ... – MattDavey

+6

¿Está seguro de que este ejemplo en particular es mucho más rápido? La JVM de Sun logra hacer que este tipo de código (en Java o Scala) sea tan rápido como C++ con la aritmética del puntero; Me sorprende que las implementaciones de C# no hagan lo mismo. –

+2

Este ejemplo particular, no, porque el compilador puede determinar que ** i ** nunca estará fuera de los límites de la matriz y, por lo tanto, omitirá las verificaciones de límites de la matriz. Pero el principio permanece. En mi caso particular, tengo un ring-buffer implementado usando un array, y un objeto Iterator separado para iterar sobre él. En este caso, el compilador no puede realizar esta optimización. – MattDavey

20

algunas mediciones de rendimiento

Las ventajas de rendimiento no son tan grandes como se podría pensar.

Realicé algunas mediciones de rendimiento del acceso a arreglos gestionados normales frente a los indicadores inseguros en C#.


Los resultados de una acumulación de ejecutar fuera de Visual Studio 2010, .NET 4, utilizando un Cualquier CPU | Versión de compilación en la siguiente especificación para PC: PC basada en x64, 1 procesador de cuatro núcleos. Familia Intel64 6 Modelo 23 Stepping 10 GenuineIntel ~ 2833 Mhz.

Linear array access 
00:00:07.1053664 for Normal 
00:00:07.1197401 for Unsafe *(p + i) 

Linear array access - with pointer increment 
00:00:07.1174493 for Normal 
00:00:10.0015947 for Unsafe (*p++) 

Random array access 
00:00:42.5559436 for Normal 
00:00:40.5632554 for Unsafe 

Random array access using Parallel.For(), with 4 processors 
00:00:10.6896303 for Normal 
00:00:10.1858376 for Unsafe 

Tenga en cuenta que el lenguaje inseguro *(p++) realidad corrió más lento. Supongo que esto rompió una optimización del compilador que combinaba la variable de bucle y el acceso al puntero (generado por el compilador) en la versión segura.

Código fuente disponible en github.

+2

-1. En ese momento, ya era un buen ejemplo de cómo NO medir el rendimiento, ya que básicamente el código de prueba es demasiado simplista. – TomTom

+0

@TomTom ¿Cómo es eso? –

+4

Es muy trivial. No tiene en cuenta las optimizaciones que el compilador puede/puede hacer. Como tal, no está claro si los números tienen algún significado. – TomTom

1

Bueno, sugeriría leer este blog post: MSDN blogs: Array Bounds Check Elimination in the CLR

Esto aclara cómo grada controles se realizan en C#. Además, las pruebas de Thomas Bratts me parecen inútiles (mirando el código) ya que el JIT elimina en sus bucles de 'salvado' los controles encuadernados de todos modos.

+2

¿Puede resumir la publicación aquí? Si el enlace se oscurece, su respuesta no será muy útil. – ChrisF

+3

Te has perdido el objetivo de las pruebas: no muestran el efecto de la comprobación de límites frente a los inseguros. Deben demostrar que la verificación de límites a menudo se optimiza y que el costo de inseguridad probablemente no valga la pena en estos casos. –

0

Estoy usando un código no seguro para el código de manipulación de video. En dicho código, desea que se ejecute lo más rápido posible sin controles internos de valores, etc.Sin atributos inseguros, mi could no podría mantenerse al día con la transmisión de video a 30 fps o 60 fps. (dependiendo de la cámara usada).

Pero debido a la velocidad es ampliamente utilizado por personas que codifican gráficos.

Cuestiones relacionadas