2010-03-25 12 views
5

I de pino para los días en que, como programador C, podría escribir:¿Cómo se compara Array.ForEach() con el ciclo estándar para C#?

memset(byte_array, '0xFF'); 

y obtener una matriz de bytes lleno de personajes 'FF'. Por lo tanto, he estado buscando un reemplazo para esto:

for (int i=0; i < byteArray.Length; i++) 
{ 
    byteArray[i] = 0xFF; 
} 

Últimamente, he estado usando algunos de los nuevos C# características y han estado utilizando este enfoque en su lugar:

Array.ForEach<byte>(byteArray, b => b = 0xFF); 

realidad, el segundo el enfoque parece más limpio y es más fácil a simple vista, pero ¿cómo se compara el rendimiento con el primer enfoque? ¿Estoy introduciendo gastos indirectos innecesarios usando Linq y genéricos?

Gracias, de Dave

+4

http://stackoverflow.com/questions/1897555/what-is-the-equivalent-of-memset-in-c – CAbbott

+4

FYI en el segundo enfoque no está utilizando LINQ. LINQ no tiene un método 'ForEach'. Está utilizando un método estático de la clase Array: 'Array.ForEach'. La expresión lambda es azúcar sintáctica para un delegado y no cuenta como LINQ. –

+0

Gracias a todos por las respuestas. Aprendí algo y espero que otros también puedan aprender algo. – DaveN59

Respuesta

7
Array.ForEach<byte>(byteArray, b => b = 0xFF); 

Esto no hace nada. Está configurando una copia de cada byte en 0xFF, nunca se establece en la matriz.

Para una manera más fácil de hacer esto, usted podría intentar

Enumerable.Repeat((byte)0xFF, someCount).ToArray(); 

para inicializar la matriz

Repetir sin duda será más lento que el de bucle. Según el enlace publicado por CAbbott en un comentario, es aproximadamente 10.5 segundos más lento (12.38 contra 1.7) en una matriz con más de un millón de elementos, pero eso no es una gran diferencia si solo lo haces unas pocas veces con pequeñas matrices.

Puede escribir un método simple que sea más rápido que Repeat y ToArray porque puede conocer la longitud de la matriz antes de comenzar a llenarla.

public static T[] GetPreFilledArray<T>(T fillItem, int count) 
    { 
     var result = new T[count]; 
     for(int i =0; i < count; i++) 
     { 
      result[i] = fillItem; 
     } 
     return result; 
    } 

    byte[] byteArray = GetPreFilledArray((byte)0xFF, 1000); 

Esa debería ser una opción bastante rápida, ya que es básicamente lo que estás haciendo ahora.

+0

¡Uy! Realmente debería probar el código que escribo antes de publicarlo. Por supuesto que está en lo correcto, el ciclo ForEach <> no funcionará mientras que el Enumerable.Repeat funciona muy bien. No responde mi pregunta sobre el problema de rendimiento, pero definitivamente es una buena información ... – DaveN59

+0

Pensándolo bien, responde la pregunta: explicaste cómo los 2 enfoques se comparan entre sí y ofrecían otra alternativa. Obtienes los puntos por este ... – DaveN59

0

A menos que usted está haciendo esto durante la operación rendimiento muy critcal, no vamos a tener un problema. Existen numerosos puntos de referencia en relación con las llamadas foreach frente a la iteración indexada, y la diferencia es mínima.

Por supuesto, siempre se puede referencia usted mismo ...

0

No creo que los genéricos jamás puede ser un menoscabo de su rendimiento. Se tratan principalmente en tiempo de compilación y su propósito general es eliminar la necesidad de conversión entre el objeto y el tipo deseado, que en el peor de los casos tendrá un efecto insignificante y, en el mejor de los casos, dará lugar a una ganancia de rendimiento mensurable.

En cuanto a LINQ, no estoy seguro de qué efectos de rendimiento puede tener.

Aunque al final las inicializaciones son una tarea menor, los efectos de rendimiento no serán nada que valga la pena.

4

El segundo método usa un delegado para configurar cada byte, esto significa que hay una llamada de método para cada byte en la matriz. Eso es mucho sobrecarga solo para establecer un byte.

El bucle simple, por otro lado, se optimiza bastante bien por el compilador. Determinará que el índice no puede estar fuera de la matriz, por lo que omitirá la comprobación de límites.

Para aclarar: No está utilizando LINQ en absoluto. El método ForEach es un método en la clase Array, y es anterior a la adición de LINQ.

1

Buffer.BlockCopy es lo que tiendo a usar cuando quiero el comportamiento tipo memset/memcpy. Mediría el rendimiento y usaría algo como el reflector. Es posible que internamente el lenguaje llame a las clases integradas, que a su vez son envoltorios delgados alrededor de MEMCPY y MEMSET.

0

He encontrado que Array.ForEach es significativamente más lento que un bucle for o foreach si los tiene en una ruta de ejecución crítica. Sin embargo, a menos que sea un desarrollador de framework/library o realmente necesite inicializar millones de matrices, no me preocuparía el rendimiento en absoluto. Es muy probable que pueda obtener mucho más optimizando en otro lugar.

Cuestiones relacionadas