【问题标题】:Converting IEnumerable<T> to List<T> on a LINQ result, huge performance loss在 LINQ 结果上将 IEnumerable<T> 转换为 List<T>,性能损失巨大
【发布时间】:2010-01-29 14:16:38
【问题描述】:

你喜欢这样的 LINQ 结果:

var result = from x in Items select x;
List<T> list = result.ToList<T>();

但是,ToList&lt;T&gt; 真的很慢,它是否使列表可变,因此转换很慢?

在大多数情况下,我可以设法只拥有我的 IEnumerableParalell.DistinctQuery,但现在我想将项目绑定到 DataGridView,因此我需要使用 IEnumerable 以外的其他东西,建议我如何将在 ToList 或任何替代品上获得性能?

IEnumerable 中的 1000 万条记录中,.ToList&lt;T&gt; 大约需要 6 秒。

【问题讨论】:

  • 您想给某人一个包含 1000 万条记录的 DataGridView?这听起来有点,嗯,笨拙。
  • 如果我可以告诉人们关于查询理解的一件事,那就是:查询理解的结果是一个查询。不是查询的结果。在您要求查询之前,您不会得到查询的结果。

标签: c# linq generics .net-4.0 c#-4.0


【解决方案1】:

.ToList()what 慢?

如果你在比较

var result = from x in Items select x;
List<T> list = result.ToList<T>();

var result = from x in Items select x;

您应该注意,由于查询是延迟评估的,因此第一行根本没有做太多事情。它不检索任何记录。 延迟执行使这种比较完全不公平

【讨论】:

  • @Filip:检索大量项目的工作量非常大。要显着提高性能,您必须更改解决问题的高级方法,以便一开始就不需要检索这么多数据
  • 好的,非常感谢您指出在我使用结果之前它不会执行。帮助我提高了其他地方的性能。 :)
【解决方案2】:

这是因为 LINQ 喜欢偷懒,做的工作越少越好。这一行:

var result = from x in Items select x;

尽管您选择了名称,但实际上并不是结果,它只是一个查询对象。它不获取任何数据。

List<T> list = result.ToList<T>();

现在您实际上已经请求了结果,因此它必须从源中获取数据并复制它。 ToList 保证制作一个副本。

考虑到这一点,第二行比第一行慢很多也就不足为奇了。

【讨论】:

  • 您确定这与数据库访问有关吗?
  • 所以在实际使用之前,查询中的任何内容都不会执行?
  • 好的,将“数据库”更改为更通用的“数据源”。但同样的逻辑也适用。
  • @Filip:是的,查询只是为您提供了一种获取数据的方法。在您需要结果之前,它实际上不会获取任何内容,如果您转换为列表,您会这样做。
  • @Filip:你真的需要一个包含一百万个元素的列表吗?你想做什么?
【解决方案3】:

不,不是创建列表需要时间,而是获取数据需要时间。

您的第一行代码实际上并没有获取数据,它只是设置了一个能够获取数据的 IEnumerable。当你调用 ToList 方法时,它实际上会获取所有数据,这就是为什么所有执行时间都在第二行。

您还应该考虑在网格中有一千万行是否有用。没有用户会浏览所有的行,因此将它们全部获取并没有任何意义。也许您应该提供一种在获取任何数据之前过滤结果的方法。

【讨论】:

    【解决方案4】:

    我认为这是因为内存重新分配:ToList 无法事先知道集合的大小,因此它可以分配足够的存储空间来保存所有项目。因此,随着它的增长,它必须重新分配List&lt;T&gt;

    如果您可以估计结果集的大小,使用 List&lt;T&gt;(int) 构造函数重载预分配足够的元素,然后手动向其中添加项目会更快。

    【讨论】:

    • 这可能是 Count() 也需要很多时间的原因。我知道它可以达到的绝对最大尺寸。 Size Items 是另一个 IEnumerable 或 List
    • @Mark 它也必须从原始数组中复制元素。
    • -1。不,这不是主要原因。用一千万个项目填充列表大约需要 0.3 秒。设置容量会将其减少到 0.1 秒,从而将其从 6 秒缩短到 5.8 秒。
    • 哎呀,对不起,没关系,你是对的。但这不是全部原因。
    猜你喜欢
    • 2012-02-24
    • 2021-12-02
    • 1970-01-01
    • 2018-08-04
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多