성능 면적으로. 루프 전에 또는 내부에 변수를 한 번 선언해야합니까?
-
06-07-2019 - |
문제
성능 현명한 점은 Foreach 문장 외부의 변수를 선언하고 매번 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;
}
물론 여기 나는 항목 개체에 대해 이야기합니다. 모두 감사합니다.
해결책
이것은 A처럼 들립니다 조기 최적화.
우선, 여기에 성능 문제가 있다고 믿을만한 이유가 있습니까?
둘째, 릴리스 빌드에서 컴파일러의 Optimizer는 아마도 두 시나리오 모두에 대해 동일한 코드를 생성 할 것입니다. - 따라서 관련이있을 것입니다. 디버그 빌드에서는 이것이 항상 사실이 아닐 수도 있지만 디버그 빌드의 의도는 코드를 정확하게 단계로 밟을 수 있기 때문에 최적화를 원하지 않습니다.
다른 팁
거기 ~이다 이것이 중요한 에지 케이스; 변수를 익명 방법 / 람다로 "캡처"하는 경우. 그렇지 않으면 그것은 조기이며 차이가 없습니다. 조금도.
문제가되는 시점의 예 :
// 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); });
}
두 개의 코드 블록으로 생성 된 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은 동일 할 것입니다. 또한 다른 사람들이 언급했듯이 문제가 될 때까지 이와 같은 것에 대해 걱정하지 마십시오. 대신, 해당 변수의 범위가 어디에 있는지 스스로에게 물어보십시오.
해당 코드 블록의 범위와 컨텍스트는이 시나리오에서는 본질적으로 조기에 조기에 불필요한 작은 성능 최적화보다 훨씬 중요합니다.