для каждого, с точки зрения производительности.Должны ли мы объявлять переменную один раз перед циклом или внутри него?

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

  •  06-07-2019
  •  | 
  •  

Вопрос

Что лучше с точки зрения производительности объявлять переменную вне foreach statment и каждый раз переназначать ее в side it (foreach) или создавать новую переменную внутри foreach например

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;
        }

или этот?

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;
        }

конечно, здесь я говорю об объекте item.спасибо вам всем.

Это было полезно?

Решение

Это звучит как преждевременная оптимизация .

Прежде всего, есть ли у вас основания полагать, что здесь есть проблема с производительностью?

Во-вторых, в релизных сборках оптимизатор компилятора, вероятно, будет генерировать идентичный код для обоих сценариев - так что он, вероятно, не имеет значения. В отладочных сборках это не всегда может быть правдой, но там вам не нужны оптимизации, поскольку цель отладочных сборок - позволить вам точно пройти по коду.

Другие советы

Там является крайний случай, когда это имеет значение;если вы "захватите" переменную в анонимный метод / lambda.В противном случае это преждевременно и не имеет никакого значения.Вообще.

Пример того, когда это действительно имеет значение:

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

против

// 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); });
}

Я почти уверен, что IL, сгенерированный вашими двумя блоками кода, идентичен. Там не должно быть никаких изменений в производительности. Однако второй блок кода, где вы объявляете тип элемента прямо там, где он используется, немного более читабелен, и я бы использовал это.

Это очень микрооптимизация, и оба метода, скорее всего, будут одинаковыми с точки зрения производительности, если не будут генерировать идентичный код. В этом случае перейдите на удобочитаемость. Я бы предпочел второе, поскольку ваш объект не имеет смысла вне цикла foreach.

Возможно, вы также можете избавиться от сохраненной ссылки все вместе:

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;
}

IL, созданный двумя блоками, должен быть почти одинаковым. Если вы хотите оптимизировать, я бы посмотрел на настройку длины окончательного списка, прежде чем заполнять его элементами. Таким образом, вы не будете наказывать за расширение длины списка.

Что-то вроде:

  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;
    }

Вероятно, компилируется в один и тот же код, но зачем его переопределять? Это хорошая вещь о ссылке, в данном случае пункт. Как только вы закончите с этим, вы можете назначить его другому ListItem и GC заботится об остальном.

Но с другой стороны читаемость для других программистов. Это решение, которое, безусловно, не приведет к существенному изменению производительности ваших приложений.

Еще лучше в вашем случае:

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;        
}

Зачем вообще создавать дополнительную переменную?

Как и предполагали все, IL будет идентичным. Кроме того, как уже упоминали другие, не беспокойтесь о таких вещах, пока они не станут проблемой. Вместо этого спросите себя, где находится область действия этой переменной.

Область и контекст этого блока кода гораздо важнее крошечных оптимизаций производительности, которые были бы преждевременными по своей природе и ненужными в этом сценарии.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top