성능 면적으로. 루프 전에 또는 내부에 변수를 한 번 선언해야합니까?

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

  •  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은 동일 할 것입니다. 또한 다른 사람들이 언급했듯이 문제가 될 때까지 이와 같은 것에 대해 걱정하지 마십시오. 대신, 해당 변수의 범위가 어디에 있는지 스스로에게 물어보십시오.

해당 코드 블록의 범위와 컨텍스트는이 시나리오에서는 본질적으로 조기에 조기에 불필요한 작은 성능 최적화보다 훨씬 중요합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top