для каждого, с точки зрения производительности.Должны ли мы объявлять переменную один раз перед циклом или внутри него?
-
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 будет идентичным. Кроме того, как уже упоминали другие, не беспокойтесь о таких вещах, пока они не станут проблемой. Вместо этого спросите себя, где находится область действия этой переменной.
Область и контекст этого блока кода гораздо важнее крошечных оптимизаций производительности, которые были бы преждевременными по своей природе и ненужными в этом сценарии.