IEnumerable 的性能

我有这个代码


List<int> items = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };

//calculation is not being executed until "even" is used

IEnumerable<int> even = items.Where(x => x % 2 == 0);   


DoStuff1(even);

DoStuff2(even);

DoStuff3(even);


当您使用 IEnumerable 时,您给编译器一个将工作推迟到以后的机会,可能会在此过程中进行优化。如果您使用 ToList(),您会强制编译器立即具体化结果。


现在这个计算(在我的例子中x % 2 == 0)是为每次调用执行DoStuff()还是以某种方式保存在内存中?


莫回无
浏览 216回答 3
3回答

DIEA

为 DoStuff() 的每次调用执行还是以某种方式保存在内存中?它本身并不保存在内存中,因此以下有时是值得优化的:IEnumerable<int> even = items.Where(x => x % 2 == 0);&nbsp; &nbsp;even = even.ToList();&nbsp; // now it is held in memoryDoStuff1(even);DoStuff2(even);DoStuff3(even);是否需要 ToList() 取决于 DoStuff() 的作用、源列表与过滤列表的大小、枚举的成本等。请注意,当items时间稍长并且所有 DoStuff 方法都有一个主循环foreach(var item in items.Take(3))时,主方法中的 ToList() 将是一个昂贵的去优化。

炎炎设计

澄清:在您的行中:IEnumerable<int>&nbsp;even&nbsp;=&nbsp;items.Where(x&nbsp;=>&nbsp;x&nbsp;%&nbsp;2&nbsp;==&nbsp;0);不计算表达式,因此实际上不会发生迭代。这就是所谓的“延迟评估”。注意:这在概念上独立于接口实现,因此无论它是 List<> 或 [] 等(当然可以针对此主要概念进行实现,但这超出了问题的范围)当您开始迭代时开始执行even,例如使用foreachor&nbsp;GetEnumerator()then&nbsp;Next()or&nbsp;FirstOrDefaultor ToList() 或 ToArray() 等。虽然我们没有看到您的DoStuffX()代码,但您可能会做类似的事情。回答您所问的主要与上述延迟评估无关:它与缓存有关。如果不缓存结果,迭代会发生多次。评估(迭代)和缓存的最简单模式是执行 ToList()var&nbsp;cached&nbsp;=&nbsp;even.ToList();(请注意,并非所有 IEnumerable 实现都允许多次迭代,但 List<> 允许。

吃鸡游戏

他怎么能把它保存在记忆中?不可能。必须执行。延迟并不意味着缓存。这意味着该行IEnumerable even = items.Where(x => x % 2 == 0);可能不执行任何操作。不是开玩笑——它可能会被推迟。然后在行中DoStuff1(偶数);它可以执行。当 items 不是内存列表而是数据库时,可能是 cmplex 的查询,人们会说“哦,我的 foreach 在它到达第一行之前花了 1 分钟”——这就是延迟的意思。在这种情况下,它只会发送 SQL 并在请求第一项时执行它。
打开App,查看更多内容
随时随地看视频慕课网APP