为了账号安全,请及时绑定邮箱和手机立即绑定

IEnumerable 的性能

IEnumerable 的性能

C#
莫回无 2021-10-31 19:01:21
我有这个代码List<int> items = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };//calculation is not being executed until "even" is usedIEnumerable<int> even = items.Where(x => x % 2 == 0);   DoStuff1(even);DoStuff2(even);DoStuff3(even);当您使用 IEnumerable 时,您给编译器一个将工作推迟到以后的机会,可能会在此过程中进行优化。如果您使用 ToList(),您会强制编译器立即具体化结果。现在这个计算(在我的例子中x % 2 == 0)是为每次调用执行DoStuff()还是以某种方式保存在内存中?
查看完整描述

3 回答

?
DIEA

TA贡献1820条经验 获得超3个赞

为 DoStuff() 的每次调用执行还是以某种方式保存在内存中?


它本身并不保存在内存中,因此以下有时是值得优化的:


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

even = even.ToList();  // now it is held in memory

DoStuff1(even);

DoStuff2(even);

DoStuff3(even);

是否需要 ToList() 取决于 DoStuff() 的作用、源列表与过滤列表的大小、枚举的成本等。


请注意,当items时间稍长并且所有 DoStuff 方法都有一个主循环foreach(var item in items.Take(3))时,主方法中的 ToList() 将是一个昂贵的去优化。


查看完整回答
反对 回复 2021-10-31
?
炎炎设计

TA贡献1808条经验 获得超4个赞

澄清:

在您的行中:

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

不计算表达式,因此实际上不会发生迭代。这就是所谓的“延迟评估”。注意:这在概念上独立于接口实现,因此无论它是 List<> 或 [] 等(当然可以针对此主要概念进行实现,但这超出了问题的范围)

当您开始迭代时开始执行even,例如使用foreachor GetEnumerator()then Next()or FirstOrDefaultor ToList() 或 ToArray() 等。

虽然我们没有看到您的DoStuffX()代码,但您可能会做类似的事情。

回答

您所问的主要与上述延迟评估无关:它与缓存有关。如果不缓存结果,迭代会发生多次。评估(迭代)和缓存的最简单模式是执行 ToList()

var cached = even.ToList();

(请注意,并非所有 IEnumerable 实现都允许多次迭代,但 List<> 允许。


查看完整回答
反对 回复 2021-10-31
?
吃鸡游戏

TA贡献1829条经验 获得超7个赞

他怎么能把它保存在记忆中?不可能。必须执行。

延迟并不意味着缓存。这意味着该行

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

可能不执行任何操作。不是开玩笑——它可能会被推迟。

然后在行中

DoStuff1(偶数);

它可以执行。

当 items 不是内存列表而是数据库时,可能是 cmplex 的查询,人们会说“哦,我的 foreach 在它到达第一行之前花了 1 分钟”——这就是延迟的意思。在这种情况下,它只会发送 SQL 并在请求第一项时执行它。


查看完整回答
反对 回复 2021-10-31
  • 3 回答
  • 0 关注
  • 215 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号