2009-08-22 14 views
6

¿Cuál es el impacto en el uso de la memoria del uso de muchos iteradores en C#? Supongamos un programa que realiza miles de bucles foreach - ¿asigna cada bucle un objeto temporal en el montón mediante una llamada al GetEnumerator? ¿Realiza el CLR algún tipo de optimización (por ejemplo, asignación de pila de objetos IEnumerator)? ¿O simplemente no es un tema lo suficientemente importante como para preocuparse?Uso de la memoria de los iteradores en C#

Respuesta

13

Simplemente no es lo suficientemente importante como para preocuparse en la mayoría de los casos. Como Eric señala, puede haber algunos casos de en los que es importante, pero son pocos y están separados en mi experiencia.

Si está haciendo cientos de miles de bucles foreach, presumiblemente está haciendo trabajo dentro de esos bucles. Es casi seguro que será más más importante que los iteradores mismos.

Tenga en cuenta que el uso de foreach en una matriz (que se sabe que es una matriz en tiempo de compilación), no utiliza IEnumerable<T> de todos modos: utiliza la indexación directa. Sin embargo, no cambiaría mi código basado en esto.

Como siempre, si le preocupa el rendimiento, debe medirlo y perfilarlo. Los cuellos de botella casi nunca están donde usted espera que estén.

+13

Aunque es, como siempre, un excelente consejo de Jon, nuestras pruebas de rendimiento mostraron un impacto significativo en el rendimiento de la asignación de montones/recolección de basura de iteradores en algunos escenarios del mundo real. Es por eso que el enumerador de la Lista es un tipo de valor mutable malvado en lugar de un tipo de referencia. Pero, por supuesto, la frase clave es "nuestras pruebas de rendimiento": como usted nota, es una tontería tomar decisiones de rendimiento sin datos. –

+2

Ah sí, el mal mutable 'lista ' iteradores - Me parece recordar una publicación de grupo de noticias con lo que parecía una pieza razonable de código pero que dio algunos resultados muy extraños debido exactamente a la decisión de diseño :) Editaré la respuesta de todos modos ... las afirmaciones generales de "no es significativo" rara vez son una buena idea. –

2

A menudo el compilador puede optimizar un bucle foreach en un bucle simple, que solo requiere una variable de índice en la pila (o en un registro de procesador).

Si todavía se utiliza un iterador, la mayoría de ellos son estructuras, por lo que solo se asignan en la pila en lugar de en el montón.

Los pocos iteradores que son clases todavía son bastante pequeños y rápidos. Podrías crear millones de ellos sin un impacto notable.

+0

Suena genial ... Pregunta de seguimiento rápida: si implemento la interfaz IEnumerable, por definición, el método GetEnumerator devuelve un IEnumerator. Si mi iterador personalizado es una estructura, supongo que, por lo tanto, se devolverá como un objeto encuadrado. –

+6

Jen, cuidadosamente, mira cómo lo hace List , y verás cómo evitar el boxeo. El truco es que * el bucle "foreach" en realidad no requiere que GetEnumerator devuelva IEnumerator *. Mientras devuelva algo que tenga las propiedades y los métodos correctos, eres dorado. De este modo puede evitar el boxeo teniendo un GetEnumerator público que devuelve una estructura y un IEnumerable .GetEnumerator explícito que devuelve una estructura encuadrada. –

+4

Pero de nuevo, como dice Jon, no hagas esto tonto a menos que tengas datos sólidos que creen enumeradores en el montón es la causa principal de un problema de rendimiento impactante para el cliente en el mundo real. Los tipos de valores mutables causan todo tipo de problemas extraños que son costosos de depurar y difíciles de entender. –

Cuestiones relacionadas