추측 해보세요 ... 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입니다.
정직하게 말하면, 200000'yield' 문장? C# 팀이 그 시간을 낭비하지 않았기 때문에 기쁩니다 ... 나는 '수익률'이 어떻게 구현되는지 결코 보지 못했지만 귀하의 대답은 거기에 있다고 생각합니다. 이 코드는 실제 코드와 얼마나 가까운지 ("실제 시나리오")? – Kobi
60ms가 완료되면 코드가 실행되기 전에 일시 중지가 발생하여 JIT 컴파일러에 문제가 있다고 가정합니다. 확률은 200,000 가지의'switch' 문을 최적화하려고 시도하고 있으며 병적 인 행동을 일으킨다. "yield"문을 너무 많이 사용하여 반복자를 사용해야하는 이유가 있습니까? – Gabe
'foreach'를 두 번 실행하십시오. 그것이 두 번째로 빠르다면, 아마 당신의 관찰을 설명하는 오버 헤드를 JITting 한 시간 일 것입니다. – Ani