猜測...當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。
老實說,200000'yield'語句?我很高興C#團隊沒有浪費他們的時間來優化那個...我從來不研究如何實現「yield」,但我想你的答案就在那裏。這與真實代碼有多接近(即「實際場景」)? – Kobi
如果你知道60ms是否完成,那麼聽起來好像暫停發生在任何代碼執行之前,這讓我認爲JIT編譯器存在問題。它有可能試圖優化200,000例'switch'語句,導致一些病態行爲。是否有任何理由需要一個帶有如此多'yield'語句的迭代器? – Gabe
執行你的'foreach'兩次。如果第二次真的很快,那可能是一次解釋你的觀察的JITting開銷。 – Ani