【问题标题】:In-memory LINQ performance内存中 LINQ 性能
【发布时间】:2010-09-13 17:22:18
【问题描述】:

不仅仅是关于 LINQ to [在此处插入您最喜欢的提供程序],这个问题是关于搜索或过滤内存中的集合。

我知道 LINQ(或搜索/过滤扩展方法)适用于实现 IEnumerableIEnumerable<T> 的对象。问题是:由于枚举的性质,每个查询的复杂度是否至少 O(n)

例如:

var result = list.FirstOrDefault(o => o.something > n);

在这种情况下,每个算法将至少花费 O(n),除非 list 相对于 'something' 排序,在这种情况下,搜索应该花费 O(log (n)):应该是二分查找。但是,如果我理解正确的话,这个查询将通过枚举来解决,所以它应该需要 O(n),即使在 list 之前已订购。

  • 有什么办法可以解决 O(log(n)) 中的查询吗?
  • 如果我想要性能,我应该使用 Array.Sort 和 Array.BinarySearch 吗?

【问题讨论】:

    标签: c# linq performance complexity-theory


    【解决方案1】:

    是的,正如 Sklivvz 所说,一般情况总是 O(n)。

    然而,当实现 IEnumerable 的对象实际实现时,许多 LINQ 方法是特例。收藏。 (我至少在 IEnumerable.Contains 中看到过这个。)

    实际上,这意味着 LINQ IEnumerable.Contains 调用快速 HashSet.Contains,例如,如果 IEnumerable 实际上是一个 HashSet。

    IEnumerable<int> mySet = new HashSet<int>();
    
    // calls the fast HashSet.Contains because HashSet implements ICollection.
    if (mySet.Contains(10)) { /* code */ }
    

    您可以使用反射器准确检查 LINQ 方法是如何定义的,这就是我的想法。

    哦,LINQ 还包含方法 IEnumerable.ToDictionary(将键映射到单个值)和 IEnumerable.ToLookup(将键映射到多个值)。这个字典/查找表可以创建一次并多次使用,可以将一些LINQ密集型代码加速几个数量级。

    【讨论】:

    • 根据问题按属性过滤时如何工作?
    • 然后您可以使用 ToDictionary 或 ToLookup,将该属性映射到字典的键,并将对象本身映射到字典的值。 (ToDircetionary 和 ToLookup 都需要委托来指定什么应该是键,什么应该是值。)
    • 当然,只有当您在未更改的结果集中对该特定属性进行足够多的搜索时,这才会加快处理速度。我认为虽然过滤/搜索属性只是一个示例,快速搜索对象本身也将包含在问题中:)
    【解决方案2】:

    即使使用并行化,它仍然是 O(n)。常数因子会有所不同(取决于您的核心数量),但随着 n 的变化,总时间仍会线性变化。

    当然,您可以在自己的数据类型上编写自己的各种 LINQ 运算符的实现,但它们仅适用于非常特定的情况 - 您必须确定谓词仅在数据的优化方面。例如,如果您有一个按年龄排序的人员列表,那么它不会帮助您进行尝试查找具有特定姓名的人的查询:)

    要检查谓词,您必须使用表达式树而不是委托,这会变得更加困难。

    我怀疑我通常会添加新的方法,让您可以清楚地看出您正在使用数据类型的索引/排序/任何性质,并且始终可以正常工作。当然,您不能轻易地从查询表达式中调用这些额外的方法,但您仍然可以使用带有点表示法的 LINQ。

    【讨论】:

      【解决方案3】:

      是的,必须如此,因为访问IEnumerable 的任何成员的唯一方法是使用它的方法,这意味着 O(n)。

      这似乎是语言设计者决定以性能换通用性的经典案例。

      【讨论】:

      • 感谢您的回答。这是我的想法。但是……没有办法规避吗?也许是并行化。
      • @Marambio:看看 PLINQ。它尝试并行化大部分 LINQ。
      猜你喜欢
      • 2012-06-22
      • 1970-01-01
      • 1970-01-01
      • 2010-12-26
      • 1970-01-01
      • 1970-01-01
      • 2011-03-27
      • 2010-11-10
      相关资源
      最近更新 更多