.NET에서 'for'또는 'foreach'중 어느 루프가 더 빨리 실행됩니까?


345

루프가 더 빨리 실행되는 C # / VB.NET / .NET에서 for 또는 foreach?

for루프보다 루프가 더 빨리 작동 한다는 것을 읽은 이후 foreach오래 전에 모든 컬렉션, 일반 컬렉션, 모든 배열 등에 적용되는 것으로 가정했습니다.

Google을 sc이 뒤져서 몇 개의 기사를 찾았지만 대부분 결론을 내리지 못하고 (기사에 대한 의견을 읽음) 공개되지 않았습니다.

이상적인 것은 각 시나리오를 나열하고 최상의 솔루션을 제시하는 것입니다.

예를 들어 (어떻게 해야하는지에 대한 예) :

  1. 1000 개 이상의 문자열 배열을 반복하는 for경우foreach
  2. IList(일반적이지 않은) 문자열 을 반복하는 foreach것보다 낫습니다.for

웹에서 몇 가지 참고 자료를 찾았습니다.

  1. Emmanuel Schanzer의 원본 그랜드 낡은 기사
  2. CodeProject FOREACH 대. 에 대한
  3. 블로그- foreach하지 말아야 할 foreach질문입니다
  4. ASP.NET 포럼-NET 1.1 C # forvsforeach

[편집하다]

가독성 측면 외에도 사실과 수치에 관심이 있습니다. 마지막 마일 성능 최적화가 중요한 응용 프로그램이 있습니다.


3
차이점은 여전히 ​​존재합니다. 특히 배열은 foreach에서 가장 빠르지 만 다른 모든 경우에는 일반 루프가 더 빠릅니다. 물론, 대부분의 경우, 이것은 차이를 만들지 않으며, 물론 현명한 JIT 컴파일러는 이론적으로 차이를 없앨 수 있습니다.
jalf December

3
컨텍스트가 없으면 정확히 무엇을하는지 알 수 없지만 부분적으로 채워진 배열을 발견하면 어떻게됩니까?
Chris Cudmore

6
그건 그렇고, 한 달에 2 백만 건의 타격은 무서운 것이 아닙니다. 평균 적중률은 1 초 미만입니다.
Mehrdad Afshari

37
중요 참고 사항 :이 질문은 어제 C # foreach대신 강제 사용에 관한 완전히 관련이없는 질문과 병합되었습니다 for. 전혀 이해가 안되는 답변이 여기에 있다면 그 이유입니다. 불운 한 대답이 아니라 중재자를 비난하십시오.
TED

7
@TED ​​아, 나는 어디에서 "모든 사장님이 바보"라고 말하는지 궁금했습니다.
Gaspa79

답변:


350

Patrick Smacchia 지난 달에 다음과 같은 결론을 내렸다.

  • List의 for 루프는 List의 foreach 루프보다 2 배 이상 저렴합니다.
  • 배열의 루핑은 목록의 루핑보다 약 2 배 저렴합니다.
  • 결과적으로 for를 사용하여 배열을 반복하는 것은 foreach를 사용하여 List를 반복하는 것보다 5 배 저렴합니다 (내 생각에 우리 모두가하는 일입니다).

130
그러나 "미리 최적화는 모든 악의 근원"이라고 잊지 마십시오.
Oorang

18
@Hardwareguy : for가 거의 인식 할 수 없을 정도로 빠름을 알고 나면 일반적으로 사용하지 않는 이유는 무엇입니까? 시간이 더 걸리지 않습니다.
DevinB September

47
@devinb, "for"를 사용하는 것은 "foreach"를 사용하는 것보다 코드, 다른 변수, 확인해야 할 조건 등을 추가하기 때문에 어렵습니다. "foreach"루프에서 한 번에 하나씩 오류가 발생했습니다 ?
tster December

35
@Hardwareguy, 내가 똑바로 가지고 있는지 보자. foreach을 사용하여 배열을 반복 하는 것보다 목록을 반복하는 데 5 배 더 오래 걸리며 for그 의미가 없다고 부르십니까? 이러한 종류의 성능 차이는 응용 프로그램에 중요 할 수도 있지만 그렇지 않을 수도 있습니다. 그러나이를 무시하지는 않습니다.
Robert Harvey

44
블로그 게시물을 읽으면 테스트가 디버그에서 실행되고 릴리스가 아닌 것처럼 실행되어 요인이 될 수 있습니다. 또한 차이점은 루프 오버 헤드에만 해당됩니다. 루프 본문을 실행하는 시간에는 전혀 영향을 미치지 않으며 대부분의 경우 목록의 다음 요소로 이동하는 데 걸리는 시간보다 훨씬 깁니다. 분명히 문제가 있음을 식별하고 앱의 차이를 구체적으로 측정했으며 눈에 띄게 개선되었지만 모든 것을 제거하는 일반적인 조언이 아니라는 것을 아는 것이 좋은 정보 foreach입니다.
Davy8

164

먼저, 반소 Dmitry의 (현재 삭제 된) 답변에 . 배열의 경우 C # 컴파일러 foreach는 동등한 for루프 와 거의 동일한 코드를 생성 합니다. 이 벤치 마크의 결과가 기본적으로 동일한 이유를 설명합니다.

using System;
using System.Diagnostics;
using System.Linq;

class Test
{
    const int Size = 1000000;
    const int Iterations = 10000;

    static void Main()
    {
        double[] data = new double[Size];
        Random rng = new Random();
        for (int i=0; i < data.Length; i++)
        {
            data[i] = rng.NextDouble();
        }

        double correctSum = data.Sum();

        Stopwatch sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j=0; j < data.Length; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum-correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in data)
            {
                sum += d;
            }
            if (Math.Abs(sum-correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop: {0}", sw.ElapsedMilliseconds);
    }
}

결과 :

For loop: 16638
Foreach loop: 16529

다음으로 컬렉션 유형에 대한 Greg의 요점에 대한 유효성 검사- List<double>위 의 배열을 a 로 변경 하면 근본적으로 다른 결과를 얻습니다. 일반적으로 속도가 상당히 느릴뿐만 아니라 foreach로 액세스하는 것보다 foreach가 상당히 느려집니다. 그럼에도 불구하고, 나는 항상 코드를 단순하게 만드는 for 루프보다 foreach를 선호합니다. 가독성은 거의 항상 중요하기 때문에 마이크로 최적화는 거의 없습니다.


"위의 배열을 List <double>로 변경하면 결과가 크게 달라집니다"매우 흥미 롭습니다.
johnc

5
내 테스트와 다른 사람들의 벤치 마크 간의 결과에 이상한 차이가 있다고 생각하면, 이것이 블로그 게시물을받을만한 가치가 있다고 생각합니다 ...
Jon Skeet

1
당신은 어떤을 거의 항상 배열과 사이 좋아 List<T>? 이 경우에도 가독성이 미세 최적화보다 우선합니까?
JohnB

12
@JohnB : 예-거의 항상 List<T>배열보다 선호 합니다. 예외는 있습니다 char[]그리고 byte[]이는 더 자주 데이터의 "덩어리"가 아닌 일반 컬렉션으로 처리됩니다.
Jon Skeet

놀랍게도, 나는 간단한 배열에서 foreach를 선호하여 내 컴퓨터에서 훨씬 더 공격적인 차이를 얻고 있습니다. 나는이 모든 것이 지터에서 비롯된 것 같아서 여분의 변수, 바운드 검사 등에 대해 걱정할 필요가 없습니다. 누군가가 이것에 대한 깊은 설명이 있다면 매우 흥미로울 것입니다.
Tamir Daniely 2016 년

162

foreach루프는보다 더 구체적 의도를 보여 for루프를 .

사용하여 foreach루프를 코드를 사용하는 모든 사람에게 컬렉션의 위치에 관계없이 컬렉션의 각 멤버에게 무언가를 수행 할 계획임을 알 수 있습니다. 또한 원본 컬렉션을 수정하지 않고 있음을 나타내며 시도하면 예외가 발생합니다.

의 또 다른 장점은 foreach그것이 어떤에서 작동한다는 것입니다 IEnumerable, 어디에 for에만 의미가 있습니다IList 각 요소가 실제로 인덱스를 보유하고 있습니다.

그러나 요소의 색인을 사용해야하는 경우에는 물론 for루프 를 사용해야합니다 . 그러나 색인을 사용할 필요가 없다면 색인을 작성하면 코드가 복잡해집니다.

내가 아는 한 성능에 큰 영향은 없습니다. 미래의 어떤 단계에서는 foreach여러 코어에서 실행 하기 위해 코드를 사용 하는 것이 더 쉬울 수 있지만 지금은 걱정할 것이 없습니다.


23
ctford : 아닙니다. 컴파일러는의 요소를 재정렬 할 수 없습니다 foreach. foreach함수형 프로그래밍과 전혀 관련이 없습니다. 그건 완전히 프로그래밍의 필수 패러다임. TPL 및 PLINQ에서 발생하는 일을에 잘못 기여하고 foreach있습니다.
Mehrdad Afshari

13
@BlueTrin : 확실히 순서를 보장합니다 (C # 사양 8.8.4는 공식적으로 루프 foreach와 동등한 것으로 정의 while). @ctford가 말하는 것을 알고 있다고 생각합니다. 작업 병렬 라이브러리를 사용 하면 기본 컬렉션 에서 .AsParallel열거 형 을 호출하여 임의의 순서로 요소를 제공 할 수 있습니다 . foreach여기서 아무것도하지 않으며 루프 본문은 단일 스레드 에서 실행됩니다 . 병렬화되는 유일한 것은 시퀀스 생성입니다.
Mehrdad Afshari

6
Enumerable.Select에는 항목의 인덱스를 얻을 수있는 오버로드가 있으므로 인덱스가 필요한 경우에도 for를 사용해야합니다. 참조 msdn.microsoft.com/en-us/library/bb534869.aspx
TrueWill

5
ForEach는 가독성과 타이핑 저장에 편리합니다. 그러나 비용은 중요합니다. 내가 만든 문서 디자이너 UI에서 2 ~ 3 개의 for-loops를 (목록의 각 obj에 대해)에서 (i = 0에서 list.count-1로) 변경하면 응답 시간이 편집 당 2-3 초에서 약으로 줄었습니다. 작은 문서에서 편집 당 5 초가 수백 개의 개체를 통해 반복됩니다. 이제 큰 문서라도 모두 반복하는 데 시간이 걸리지 않습니다. 나는 이것이 어떻게 일어 났는지 전혀 모른다. 내가 아는 것은 대안이 객체의 하위 세트 만 반복하는 복잡한 체계라는 것입니다. 나는 매일 5 분만 갈 게요! - 미세 최적화가 아닙니다 .
FastAl

5
@FastAl 일반 목록의 성능 foreach과 차이점은 for수백만 개가 넘는 항목을 반복하는 데있어 1 초에 불과하므로 적어도 수백 개의 개체가 아닌 foreach 성능과 직접 관련이 없었습니다. 사용중인 모든 목록에서 깨진 열거 형 구현처럼 들립니다.
Mike Marynowski

53

성능에 대한 논쟁이있을 때마다, 당신은 당신의 사례를 지원하기 위해 양적 결과를 사용할 수 있도록 작은 테스트를 작성하면됩니다.

StopWatch 클래스를 사용하고 정확성을 위해 수백만 번 반복하십시오. (for 루프가 없으면 어려울 수 있습니다) :

using System.Diagnostics;
//...
Stopwatch sw = new Stopwatch()
sw.Start()
for(int i = 0; i < 1000000;i ++)
{
    //do whatever it is you need to time
}
sw.Stop();
//print out sw.ElapsedMilliseconds

손가락은이 쇼의 결과를 넘어서 그 차이는 무시할 만하다는 것을 보여 주며 가장 유지 보수가 쉬운 코드로 결과를 얻을 수 있습니다.


13
그러나 for 및 foreach의 성능을 비교할 수는 없습니다. 그들은 다른 상황에서 사용되어야합니다.
Michael Krelin-해커

7
Michael에 동의합니다. 성능에 따라 사용할 것을 선택해서는 안됩니다. 가장 적합한 것을 선택해야합니다! 그러나 상사가 "foreach보다 느리기 때문에 사용하지 마십시오"라고 말하면 이것이 차이를 무시할 수 있음을 확신시키는 유일한 방법입니다
Rob Fonseca-Ensor

"(for 루프가 없으면 어려울 수 있습니다.") 또는 while 루프를 사용할 수 있습니다.
jonescb 2009

49

항상 가깝습니다. 배열의 경우 때로는 for 약간 빠르지 만 foreach표현력이 뛰어나고 LINQ 등을 제공합니다. 일반적으로으로 고정하십시오 foreach.

또한 foreach일부 시나리오에서 최적화 될 수 있습니다. 예를 들어, 링크 된 목록은 인덱서에 의해 끔찍할 수 있지만으로 빠를 수 있습니다 foreach. 실제로이 표준 LinkedList<T>은 이러한 이유로 인덱서를 제공하지도 않습니다.


그래서 당신 LinkedList<T>은보다 더 마른 List<T>말입니까? 그리고 항상 foreach(대신 for) 대신 사용하려고한다면 LinkedList<T>?를 사용하는 것이 좋습니다 .
JohnB

2
@JohnB-뛰어나지 않음; 그냥 다릅니다. 예를 들어, 링크 된 목록의 각 노드에는 플랫 배열에 필요하지 않은 추가 참조가 있습니다 (이 또한 기반이됩니다 List<T>). 삽입 / 제거 가 더 저렴합니다 .
Marc Gravell

36

내 생각에 99 %의 경우에는 그다지 중요하지 않을 것입니다. 왜 가장 이해하기 쉬운 것보다 가장 빠른 것 대신 더 빠른 것을 선택하겠습니까?


6
@ klew, 실제로 코드를 프로파일 링하면 가능한 20 %가 빠를 필요가 있다고 추측 할 필요가 없습니다. 또한 빠른 속도가 필요한 실제 루프 수가 훨씬 적다는 것을 알 수 있습니다. 또한, 루프에서 실제로하는 일과 달리 루핑 동작이 시간을 보내는 곳이라고 말하고 있습니까?
tster December

32

둘 사이에 큰 성능 차이는 없을 것입니다. 항상 그렇듯이 "더 빠를까?" 질문, 당신은 항상 "나는 이것을 측정 할 수 있습니다"라고 생각해야합니다.

루프 본문에서 동일한 작업을 수행하는 두 개의 루프를 작성하고 둘 다 실행하고 시간을 정한 다음 속도의 차이가 무엇인지 확인하십시오. 거의 빈 바디와 실제로 수행 할 작업과 유사한 루프 바디로이 작업을 수행하십시오. 컬렉션 유형에 따라 성능 특성이 다를 수 있으므로 사용중인 컬렉션 유형으로 시도하십시오.


32

루프보다 루프 를 선호하는 데는 매우 좋은 이유가 있습니다. 루프 를 사용할 수 있다면 상사가 옳 아야합니다.foreachforforeach

그러나 모든 반복이 단순히 순서대로 목록을 통과하는 것은 아닙니다. 그가 금지 한다면 하고 , 그렇습니다.

내가 너라면, 내가 할 일은 자연스럽게 for 루프를 모두 재귀로 바꾸는 것입니다. 입니다. 그것은 그에게 가르쳐 줄 것이며, 그것은 또한 당신에게 좋은 정신 운동입니다.


재귀는 for루프 를 루프와 foreach성능 측면에서 어떻게 비교 합니까?
JohnB

때에 따라 다르지. 꼬리 재귀를 사용하고 컴파일러가 알아 차릴 정도로 똑똑하다면 동일 할 수 있습니다. OTOH : 그렇지 않으면 많은 비 필요한 (변경되지 않은) 데이터를 매개 변수로 전달하거나 스택의 큰 구조를 로컬로 선언하는 것처럼 바보 같은 일을하면 실제로 느려질 수 있습니다 (또는 RAM이 부족할 수도 있음).
TED

아 네가 왜 그랬는지 알아 이 답변은 완전히 다른 질문에 갔다. 어리석은 이유로 조나단 샘슨은 어제 두 사람을 합병했다. 그는 정말로 그렇게해서는 안됩니다. 병합 된 답변은 여기에서 의미가 없습니다.
TED

18

TechEd 2005의 Jeffrey Richter :

"수년에 걸쳐 C # 컴파일러는 기본적으로 거짓말 쟁이입니다." .. "많은 것들에 관한 것입니다." .. "foreach 루프를 수행 할 때처럼 ...".. "... 작은 한 줄의 코드이지만, C # 컴파일러가 놀라운 결과를 내기 위해 뱉어내는 것입니다. try / finally block, finally 블록 내부에서 변수를 IDisposable 인터페이스로 캐스팅하고 캐스트가 성공하면 Dispose 메서드를 호출하고 루프 내에서 Current 속성과 MoveNext 메서드를 반복하여 루프 내에서 반복합니다. 많은 사람들이 코딩하기 매우 쉽고 수행하기 쉽기 때문에 foreach를 사용합니다. ".."foreach는 성능 측면에서 그리 좋지 않습니다

주문형 웹 캐스트 : http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032292286&EventCategory=3&culture=en-US&CountryCode=US


12

이건 말도 안돼 for 루프, 성능 측면 또는 기타를 금지해야 할 강력한 이유는 없습니다.

성능 벤치 마크 및 기타 인수에 대해서는 Jon Skeet의 블로그 를 참조하십시오 .


2
업데이트 된 링크 : codeblog.jonskeet.uk/2009/01/29/…
Matt

더 빠른 루프 구성은 반복해야 할 대상에 따라 다릅니다. DataRow 및 사용자 지정 개체와 같은 여러 종류의 개체에 대한 여러 반복을 벤치마킹하는 다른 블로그입니다 . 또한 for 및 foreach 루프 구성뿐만 아니라 While 루프 구성의 성능도 포함합니다.
무료 코더 24

11

객체 컬렉션으로 작업하는 foreach것이 더 좋지만 숫자를 늘리면for 루프가 좋습니다.

마지막 경우 다음과 같은 작업을 수행 할 수 있습니다.

foreach (int i in Enumerable.Range(1, 10))...

그러나 확실히 더 잘 수행되지는 않습니다. 실제로에 비해 성능이 떨어집니다 for.


"더 나은"논란의 여지가있다 : 속도가 느리고 dnspy ​​디버거가 C # foreach로 침입하지는 않는다 (VS2017 디버거가 할지라도). 때로는 더 읽기 쉽지만 언어가없는 언어를 지원하면 성 가실 수 있습니다.
Zeek2

10

이것은 당신을 저장해야합니다 :

public IEnumerator<int> For(int start, int end, int step) {
    int n = start;
    while (n <= end) {
        yield n;
        n += step;
    }
}

사용하다:

foreach (int n in For(1, 200, 4)) {
    Console.WriteLine(n);
}

더 큰 승리를 위해 세 명의 대의원을 매개 변수로 사용할 수 있습니다.


1
한 가지 작은 차이점은 for일반적으로 범위의 끝을 제외하도록 루프가 작성된다는 것입니다 (예 :) 0 <= i < 10. Parallel.For또한 공통 for루프 와 쉽게 호환되도록 유지합니다 .
Groo

9

Deep .NET 에서 읽을 수 있습니다 -1 부 반복

.NET 소스 코드에서 디스 어셈블리까지의 결과 (첫 번째 초기화없이)를 다룹니다.

예를 들어-foreach 루프를 사용한 배열 반복 : 여기에 이미지 설명을 입력하십시오

그리고-foreach 루프로 반복 목록을 작성하십시오. 여기에 이미지 설명을 입력하십시오

그리고 최종 결과 : 여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오


8

for-및- foreach루프 에서 속도의 차이는 배열, 목록 등과 같은 일반적인 구조를 반복 할 때 작습니다.LINQ 컬렉션에 쿼리를 것이 거의 느리지 만 작성하는 것이 더 좋습니다! 다른 포스터가 말했듯이 밀리 초의 추가 성능보다는 표현력을 얻으십시오.

지금까지 말하지 않은 것은 foreach루프가 컴파일 될 때 반복되는 컬렉션을 기반으로 컴파일러에 의해 최적화된다는 것입니다. 즉, 어떤 루프를 사용해야하는지 확실하지 않으면 루프를 사용해야합니다. foreach루프가 컴파일 될 때 가장 적합한 루프를 생성합니다. 더 읽기 쉽습니다.

foreach루프의 또 다른 주요 장점 은 컬렉션 구현이 int array에서 List<int>for로 foreach변경되면 루프에서 코드를 변경할 필요가 없다는 것입니다.

foreach (int i in myCollection)

위의 내용은 컬렉션의 유형에 관계없이 동일하지만 for루프 myCollection에서 a array에서 a로 변경하면 다음이 빌드되지 않습니다 List.

for (int i = 0; i < myCollection.Length, i++)

7

"for 루프를 사용할 수 있는지 확인하는 데 사용할 수있는 인수가 있습니까?"

아니, 당신의 상사가 어떤 프로그래밍 언어 구성을 사용하는지 말해 줄 수있는 수준까지 미시 관리하고 있다면, 실제로 말할 수있는 것은 없습니다. 죄송합니다.


7

아마도 열거하고있는 컬렉션 유형과 인덱서 구현에 따라 다릅니다. 그러나 일반적으로 사용 foreach하는 것이 더 나은 방법 일 수 있습니다.

또한 IEnumerable인덱서가 아닌 모든 항목에서 작동합니다 .


7

여기에는 가장 "빠른"질문과 같은 두 가지 대답이 있습니다.

1) 측정하지 않으면 모릅니다.

2) (왜냐하면 ...) 상황에 따라 다릅니다.

반복 할 IEnumerable의 유형 (또는 유형)에 대해 "this [int index]"메소드의 가격과 비교하여 "MoveNext ()"메소드의 가격에 따라 다릅니다.

"foreach"키워드는 일련의 작업에 대한 약어입니다. IEnumerable에서 GetEnumerator ()를 한 번 호출하고, 반복마다 한 번 MoveNext ()를 호출하고, 유형 검사 등을 수행합니다. 성능 측정에 가장 영향을 줄 수있는 것은 O (N) 번 호출되기 때문에 MoveNext ()의 비용입니다. 아마도 싸지 만 아닐 수도 있습니다.

"for"키워드는 더 예측 가능해 보이지만 대부분의 "for"루프 안에서 "collection [index]"와 같은 것을 찾을 수 있습니다. 이것은 간단한 배열 인덱싱 작업처럼 보이지만 실제로는 메서드 호출이며 비용은 전적으로 반복하는 컬렉션의 특성에 달려 있습니다. 아마 싸지 만 아닐 수도 있습니다.

컬렉션의 기본 구조가 본질적으로 연결된 목록 인 경우 MoveNext는 비싸지 만 인덱서에는 O (N) 비용이있을 수 있으므로 "for"루프 O (N * N)의 실제 비용이 발생합니다.


6

모든 언어 구성에는 사용하기에 적절한 시간과 장소가 있습니다. C # 언어에 네 개의 개별 반복문 이있는 이유가 있습니다 . 가 있습니다. 각 은 특정 목적을 위해 사용되며 적절하게 사용됩니다.

나는 상사와 함께 앉아 왜 for루프에 목적이 있는지 합리적으로 설명하려고합니다 . 경우가 있습니다 for반복 블록이 더 명확보다 알고리즘을 설명 foreach반복합니다. 이것이 사실이면 그것들을 사용하는 것이 적절합니다.

나는 또한 당신의 상사에게 지적 할 것입니다-성능은 실제적인 방법으로 문제가되지 않아야하며 어떤 식으로도 문제가되어서는 안됩니다. 알고리즘을 간결하고 의미 있고 유지 보수가 가능한 방식으로 표현하는 것이 더 중요합니다. 이와 같은 마이크로 최적화는 성능 최적화의 요점을 완전히 벗어납니다. 왜냐하면 실제 성능상의 이점은 루프 구조 조정이 아니라 알고리즘 재 설계 및 리팩토링에서 비롯되기 때문입니다.

합리적인 토론 후에도 여전히 권위 주의적 견해가 있다면, 어떻게 진행할 것인지는 당신에게 달려 있습니다. 개인적으로 저는 합리적인 사고가 권장되지 않는 환경에서 일하는 것을 좋아하지 않으며 다른 고용주 아래 다른 위치로 이사하는 것을 고려할 것입니다. 그러나 화를 내기 전에 토론을 강력히 권장합니다. 간단한 오해가있을 수 있습니다.


5

실제 루핑 구조가 아니라 루프 내부 에서 수행 하는 것이 성능에 영향을 미칩니다 (사례가 중요하지 않다고 가정).


5

요점 for보다 더 빠른지 아닌지 foreach. 하나를 선택하면 성능에 큰 영향을 줄 것입니다.

응용 프로그램을 최적화하는 가장 좋은 방법은 실제 코드를 프로파일 링하는 것입니다. 그것은 가장 많은 일과 시간을 설명하는 방법을 정확하게 보여줄 것입니다. 먼저 최적화하십시오. 여전히 성능이 만족스럽지 않으면 절차를 반복하십시오.

일반적으로 마이크로 최적화는 별다른 이점이 없기 때문에 마이크로 최적화를 피하는 것이 좋습니다. 식별 된 핫 경로를 최적화 할 때만 예외입니다 (예 : 프로파일 링에서 자주 사용되는 몇 가지 방법을 식별하는 경우 광범위하게 최적화하는 것이 합리적 일 수 있습니다).


내가 작업하는 프로젝트에서 내가해야했던 유일한 종류의 최적화가 마이크로 최적화라면, 나는 행복한 야영 자입니다. 슬프게도, 이것은 사실이 아닙니다.
Yannick Motton 2009

2
for보다 약간 빠릅니다 foreach. 나는이 진술에 진지하게 반대한다. 그것은 전적으로 기본 컬렉션에 달려 있습니다. 연결된 목록 클래스가 인덱서에 정수 매개 변수를 제공하는 경우 for루프를 사용하면 O (n ^ 2)이고 foreachO (n)이 될 것으로 예상됩니다.
Mehrdad Afshari

@Merhdad : 사실 좋은 지적입니다. 방금 목록 (예 : 배열)을 색인화하는 일반적인 경우에 대해 생각하고있었습니다. 나는 그것을 반영하기 위해 다시 말하겠다. 감사.
Brian Rasmussen

@Mehrdad Afshari : 정수로 컬렉션을 인덱싱하는 것은 컬렉션을 열거하는 것보다 훨씬 느릴 수 있습니다 . 그러나 실제로 사용 for 인덱서 조회를 foreach자체 사용 비교 하고 있습니다. @Brian Rasmussen의 대답은 컬렉션과 함께 사용하는 것 외에도 for항상보다 약간 빠릅니다 foreach. 그러나 for컬렉션 룩업은 항상 foreach그 자체 보다 느립니다 .
Daniel Pryden 2009

@Daniel : 일반 배열이 있거나 둘 다 동일한 코드를 생성하거나 for명령문 을 사용할 때 인덱서가 있습니다 . for정수 제어 변수가있는 평범한 루프는와 비교할 수 foreach없으므로 빠져 있습니다. @Brian이 의미하는 바를 이해하며 귀하가 말한대로 정확하지만 답변이 잘못 될 수 있습니다. 다시 : 마지막 요점 : 아니오, 실제로, for이상 List<T>은 여전히보다 빠릅니다 foreach.
Mehrdad Afshari

4

둘은 거의 똑같은 방식으로 실행됩니다. 둘 다 사용하는 코드를 작성한 다음 IL을 보여주십시오. 성능에 차이가 없음을 의미하는 유사한 계산을 보여 주어야합니다.


컴파일러는 배열 / IList 등에 사용 된 foreach 루프를 인식하여 for 루프로 변경합니다.
Callum Rogers

3
그에게 괜찮다는 지울 줄 모르는 증거를 보여주고 그것이 틀렸다는 증거 를 요구하십시오.
cjk

3

for 구현하는 데 더 간단한 로직이 있으므로 foreach보다 빠릅니다.


3

특정 속도 최적화 프로세스를 수행하지 않는 한 코드를 읽고 유지 관리하기 가장 쉬운 방법을 사용한다고 말합니다.

컬렉션 클래스 중 하나와 같이 반복자가 이미 설정되어 있으면 foreach가 좋은 옵션입니다. 그리고 그것이 반복하는 정수 범위라면 아마도 더 깨끗할 것입니다.



3

대부분의 경우 실제로 차이가 없습니다.

일반적으로 명시적인 숫자 인덱스가없는 경우 항상 foreach를 사용해야하며 실제로 반복 가능한 컬렉션이없는 경우에는 항상 사용해야합니다 (예 : 위 삼각형의 2 차원 배열 그리드에서 반복) . 선택의 여지가있는 경우가 있습니다.

마법의 숫자가 코드에 나타나기 시작하면 for 루프를 유지하는 것이 조금 더 어려울 수 있다고 주장 할 수 있습니다. for 루프를 사용할 수 없어 짜증이 나고 for 루프가 금지되어 있기 때문에 대신 컬렉션을 빌드하거나 람다를 사용하여 하위 컬렉션을 빌드해야합니다.


3

for 루프와 같은 것을 사용하는 것을 완전히 금지하는 것은 조금 이상합니다.

두 루프 사이의 많은 성능 차이를 다루는 흥미로운 기사가 있습니다 .

나는 개인적으로 foreach가 for 루프보다 조금 더 읽기 쉽다고 말하지만, 현재 작업에 가장 적합해야하며 for 루프가 더 적합한 경우 foreach 루프를 포함하기 위해 긴 코드를 작성할 필요가 없습니다.


"... 컬렉션이 아닌 고성능 코드를 작성하려는 경우 루프를 사용하십시오. 컬렉션에서도 foreach를 사용하면 편리해 보일 수 있지만 그렇게 효율적이지 않습니다."
NickFitz 2009

3

나는 foreach루프가 List 더 빨리 반복되는 것을 발견했다 . 아래의 테스트 결과를 참조하십시오. 아래 코드 에서 시간을 측정하기 위해 및 루프를 array사용하여 별도로 크기가 100, 10000 및 100000 인 반복합니다.forforeach

여기에 이미지 설명을 입력하십시오

private static void MeasureTime()
    {
        var array = new int[10000];
        var list = array.ToList();
        Console.WriteLine("Array size: {0}", array.Length);

        Console.WriteLine("Array For loop ......");
        var stopWatch = Stopwatch.StartNew();
        for (int i = 0; i < array.Length; i++)
        {
            Thread.Sleep(1);
        }
        stopWatch.Stop();
        Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("Array Foreach loop ......");
        var stopWatch1 = Stopwatch.StartNew();
        foreach (var item in array)
        {
            Thread.Sleep(1);
        }
        stopWatch1.Stop();
        Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch1.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("List For loop ......");
        var stopWatch2 = Stopwatch.StartNew();
        for (int i = 0; i < list.Count; i++)
        {
            Thread.Sleep(1);
        }
        stopWatch2.Stop();
        Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch2.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("List Foreach loop ......");
        var stopWatch3 = Stopwatch.StartNew();
        foreach (var item in list)
        {
            Thread.Sleep(1);
        }
        stopWatch3.Stop();
        Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch3.ElapsedMilliseconds);
    }

업데이트

@jgauffin 제안 후 @johnskeet 코드를 사용하고 for루프 array가 다음보다 빠르다는 것을 알았 습니다.

  • 배열이있는 Foreach 루프.
  • 목록이있는 루프.
  • 목록이있는 Foreach 루프.

아래의 테스트 결과와 코드를 참조하십시오.

여기에 이미지 설명을 입력하십시오

private static void MeasureNewTime()
    {
        var data = new double[Size];
        var rng = new Random();
        for (int i = 0; i < data.Length; i++)
        {
            data[i] = rng.NextDouble();
        }
        Console.WriteLine("Lenght of array: {0}", data.Length);
        Console.WriteLine("No. of iteration: {0}", Iterations);
        Console.WriteLine(" ");
        double correctSum = data.Sum();

        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j = 0; j < data.Length; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop with Array: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (var i = 0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in data)
            {
                sum += d;
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop with Array: {0}", sw.ElapsedMilliseconds);
        Console.WriteLine(" ");

        var dataList = data.ToList();
        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j = 0; j < dataList.Count; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop with List: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in dataList)
            {
                sum += d;
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop with List: {0}", sw.ElapsedMilliseconds);
    }

3
이것은 매우 열악한 테스트입니다. a) 결정적인 대답을 얻기에는 반복이 너무 적습니다. b) 해당 Thread.Sleep은 실제로 1 밀리 초를 기다리지 않습니다. Jon Skeet의 답변과 동일한 방법을 사용하십시오.
jgauffin 2016 년

1
99.99 %의 시간이 thread.sleep에 확실히 사용됩니다 (최소한 시간 전에는 그렇지 않은 경우를 제외하고는 얼마나 빨리 리턴되는지 보장하지 않습니다). 루핑은 매우 빠르며 수면은 매우 느리므로 후자를 사용하여 전자를 테스트하지 않습니다.
Ronan Thibaudau

3

실제로 그의 머리를 조이고 대신 IQueryable .foreach 클로저를 사용할 수 있습니다.

myList.ForEach(c => Console.WriteLine(c.ToString());

3
코드 줄을로 바꿉니다 myList.ForEach(Console.WriteLine).
Mehrdad Afshari

2

나는 그 둘 사이에 "거대한"성능 차이를 찾을 사람이 없을 것입니다.

대답은 액세스하려는 컬렉션에 더 빠른 인덱서 액세스 구현이 있는지 또는 IEnumerator 액세스 구현이 더 빠른지 여부에 달려 있습니다. IEnumerator는 종종 인덱서를 사용하고 현재 인덱스 위치의 복사본 만 보유하므로 열거 자 액세스는 직접 인덱스 액세스보다 느리거나 느리지 만 많이는 아닙니다.

물론이 답변은 컴파일러가 구현할 수있는 최적화를 설명하지 않습니다.


C # 컴파일러는 최적화를 거의하지 않으므로 실제로 JITter에 맡깁니다.
ljs

JITter는 컴파일러입니다. 그렇죠?
JohannesH

2

for-loop와 foreach-loop는 항상 같은 것은 아닙니다. 목록이 변경되면 목록 열거자가 예외를 throw하지만 항상 일반적인 for 루프와 함께 경고가 표시되는 것은 아닙니다. 목록이 잘못된 시간에 변경되면 다른 예외가 발생할 수도 있습니다.


목록이 아래에서 바뀌면 foreach 루프를 뒷받침하는 열거자를 사용할 수 없습니다. 값을 반환 한 후에는 다시 검사하지 않으므로 경쟁이 발생합니다.
hoodaticus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.