foreach, en cuanto al rendimiento. ¿Deberíamos declarar variable una vez antes del bucle o dentro de él?

StackOverflow https://stackoverflow.com/questions/1632444

  •  06-07-2019
  •  | 
  •  

Pregunta

¿Qué es mejor para el rendimiento sabio declarando la variable fuera del foreach y cada vez que la reasigne a un lado (foreach) o cree una nueva variable dentro de foreach por ejemplo

private List<ListItem> GetItems()
        {
            var items = new List<ListItem>();
            var collection = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            ListItem item;
            foreach (var i in collection)
            {
                item = new ListItem { Text = i.ToString() };
                items.Add(item);
            }

            return items;
        }

o este?

private List<ListItem> GetItems()
        {
            var items = new List<ListItem>();
            var collection = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
            foreach (var i in collection)
            {
                ListItem item = new ListItem { Text = i.ToString() };
                items.Add(item);
            }

            return items;
        }

seguro aquí estoy hablando del objeto objeto. gracias a todos

¿Fue útil?

Solución

Esto suena como una optimización prematura .

En primer lugar, ¿tiene alguna razón para creer que hay un problema de rendimiento aquí?

Segundo, en las versiones de lanzamiento, el optimizador del compilador probablemente producirá un código idéntico para ambos escenarios , por lo que es probable que sea irrelevante. En las compilaciones de depuración, esto puede no ser siempre cierto, pero allí no desea optimizaciones ya que la intención de las compilaciones de depuración es permitirle avanzar con precisión por el código.

Otros consejos

Hay un caso de borde donde esto importa; si usted "captura" la variable en un método anónimo / lambda. De lo contrario, es prematuro y no hace ninguna diferencia. En absoluto.

Un ejemplo de cuándo importa:

// prints all items in no particular order
foreach (var i in collection)
{
    string s = i.ToString();
    ThreadPool.QueueUserWorkItem(delegate { Console.WriteLine(s); });
}

vs

// may print the same item each time, or any combination of items; very bad
string s;
foreach (var i in collection)
{
    s = i.ToString();
    ThreadPool.QueueUserWorkItem(delegate { Console.WriteLine(s); });
}

Estoy bastante seguro de que la IL generada por sus dos bloques de código es idéntica. No debería haber ningún cambio en el rendimiento. Sin embargo, el segundo bloque de código donde declaras el tipo de elemento justo donde se usa es un poco más legible y lo usaría.

Esta es una optimización muy micro y es probable que ambos métodos tengan exactamente el mismo rendimiento, si no generan un código idéntico. En este caso, busque legibilidad. Preferiría el segundo, ya que su objeto no sirve para nada fuera del bucle foreach.

Podría decirse que también podría deshacerse de la referencia almacenada:

private List<ListItem> GetItems()
{
  var items = new List<ListItem>();
  var collection = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

  foreach (var i in collection)
  {
    items.Add(new ListItem { Text = i.ToString() });
  }

  return items;
}

La IL creada por los dos bloques debería ser casi la misma. Si está buscando optimizar, buscaría establecer la longitud de la lista final antes de llenarla con elementos. De esa manera no será la penalización de expansión por extender la longitud de la lista.

Algo así como:

  private List<ListItem> GetItems()
    {
        var collection = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        var items = new List<ListItem>(collection.Count);  //declare the amount of space here

        foreach (var i in collection)
        {
            ListItem item = new ListItem { Text = i.ToString() };
            items.Add(item);
        }

        return items;
    }

Probablemente compila el mismo código, pero ¿por qué molestarse en volver a declararlo? Eso es lo bueno de la referencia, en este caso el artículo. Una vez que haya terminado con él, puede asignarlo a otro ListItem y al GC Se encarga del resto.

Pero, por otro lado, legibilidad para otros programadores. Es una decisión que ciertamente no cambiará drásticamente el rendimiento de sus aplicaciones.

Aún mejor en su caso es:

private List<ListItem> GetItems()        
{            
   var items = new List<ListItem>();            
   var collection = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };            
   foreach (var i in collection)            
      items.Add(new ListItem { Text = i.ToString() });                 
   return items;        
}

¿Por qué crear una variable adicional?

Como todos han especulado, la IL será idéntica. Además, como otros han mencionado, no se preocupe por cosas como esta hasta que se conviertan en un problema. En cambio, pregúntese a dónde pertenece el alcance de esa variable.

El alcance y el contexto de ese bloque de código es mucho más importante que las pequeñas optimizaciones de rendimiento que serían de naturaleza prematura e innecesarias en este escenario.

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