2011-11-24 4 views
4

추측 해보세요 ... i == 0 일 때이 프로그램이 첫 번째 출력을 생성하는 데 얼마나 오래 걸릴까요? 순식간이 겠지? 그리고 yield의 게으른 평가를 통해 그 후에 출력을 신속하게 연속 생성해야합니다. 맞습니까?IEnumerable/yield를 사용하여 이상한 동작을 설명하십시오.

static void Main(string[] args) 
{ 
    Stopwatch stopwatch = Stopwatch.StartNew(); 
    int i = 0; 
    foreach (var item in massiveYieldStatement()) 
    { 
     if (i++ % 10000 == 0) 
      Console.WriteLine(stopwatch.ElapsedMilliseconds/1000); 
    } 
    Console.ReadKey(); 
} 

static IEnumerable<string> massiveYieldStatement() 
{ 
    yield return "a"; 
    yield return "a"; 

    .. repeat 200,000 times !! 

    yield return "a"; 
} 

하지만 그렇지 않습니다! 거기에 4 ~ 21 분 동안 아무런 출력이 없으며 한 번에 60ms 미만으로 빠르게 완료됩니다! 이 기간 동안 한 코어의 CPU 사용량이 100 % 사용되며 메모리 사용량이 증가합니다. 실제 시나리오에서 나는이 첫 번째 반복이 발생하기 전에 Stackoverflow 예외가 발생했습니다! Visual Studio에서 디버그 모드로, 명령 프롬프트에서 릴리스 모드로 시도했습니다. Windows 7 x64 및 Windows Server 2008 R2 x64에서 사용 해보았습니다.

여기에 무슨 일이 일어 났는지 설명 할 수 있습니까? 그것은 당신을 위해 repro?

참고 : 실제 코드는 아닙니다. 실제 코드는 훨씬 적은 수율 문을 가지고 있지만 훨씬 더 복잡합니다. 이것은 단지 간단한 repro입니다.

+3

정직하게 말하면, 200000'yield' 문장? C# 팀이 그 시간을 낭비하지 않았기 때문에 기쁩니다 ... 나는 '수익률'이 어떻게 구현되는지 결코 보지 못했지만 귀하의 대답은 거기에 있다고 생각합니다. 이 코드는 실제 코드와 얼마나 가까운지 ("실제 시나리오")? – Kobi

+4

60ms가 완료되면 코드가 실행되기 전에 일시 중지가 발생하여 JIT 컴파일러에 문제가 있다고 가정합니다. 확률은 200,000 가지의'switch' 문을 최적화하려고 시도하고 있으며 병적 인 행동을 일으킨다. "yield"문을 너무 많이 사용하여 반복자를 사용해야하는 이유가 있습니까? – Gabe

+1

'foreach'를 두 번 실행하십시오. 그것이 두 번째로 빠르다면, 아마 당신의 관찰을 설명하는 오버 헤드를 JITting 한 시간 일 것입니다. – Ani

답변

4

이 코드로 생성 된 어셈블리는 수 MB입니다. yield return은 믿을 수 없을만큼 단순 해 보이지만 C# 컴파일러는 실제로 massiveYieldStatement 메서드를 구현하는 클래스 ('상태 시스템')를 생성한다는 점에서 특별한 짐승입니다. 나는 JIT 컴파일러가 그 클래스의 MoveNext() 메소드를 컴파일하기를 기다리고 있다고 확신한다. (ildasm으로 확인할 수있다 : MoveNext() 메소드를 열려고하면 많은 시간이 걸린다.).

+0

예, ildasm도 넘어집니다. –

2

문제는 양보가 아니지만 200K를 반환하는 함수 (btw. 100K 선은 이미 내 VS 속도가 느려졌습니다). IEnumerable<string>.GetEnumerator에서 반환 된 IEnumerator에서 처음으로 MoveNext()을 수행 할 때마다 새로운 상태 클래스를 생성하고 평가해야합니다.

static IEnumerable<string> massiveYieldStatement() 
{ 
    for(int i = 0; i < 200000; ++i) 
     yield return "a"; 
} 

은 평가가 빠르기 때문에 예상대로 빨리 실행됩니다.

관련 문제