2013-03-20 49 views
3

的IEnumerable 结果我了解LINQ延迟执行如下解释: What are the benefits of a Deferred Execution in LINQ? 从方法和延迟执行

然而,延迟执行可导致尤其是在多线程方案如错误。在锁之外的共享集合上执行评估。当一个返回延迟评估的方法嵌套多个方法层时,它可能会非常难以记住或保持跟踪,以便适当锁定。

忽略像无限序列(如Fibonacci)这样的特殊情况,并且假设集合的过滤被认为是完全的(即消费者不太可能会进一步过滤结果),那么会被认为是“最好的方法“从一个方法返回一个IEnumerable集合时 - 是否应该评估或推迟?

注意:“最佳方法”可以根据其他度量的效率/代码安全性来定义,只需在您的响应中进行验证即可。我想知道社区如何做到这一点。

后续问题:在方法名称中明确声明结果是否被评估或推迟是否有意义?

回答

2

你写的大部分代码不是多线程的。事实上,只有三个原因,我能想到,当你想急切地评估一个枚举的:

  1. 你需要它在多线程环境。你应该把它变成一个列表或数组。
  2. 你想随机访问可枚举。你应该把它变成一个列表或数组。
  3. 您想控制何时进行评估(例如,如果价格昂贵)。

在其他时间,你应该让它使用延迟执行。这将评估推迟到实际需要的时间点,并且可能会更快,具体取决于您应用的过滤器。例如,bigquery.First()可能会比bigquery.ToArray().First()更快。你能否确定用户完成了过滤?

另外,运行时will optimize certain LINQ queries。这个例子是从Jon Skeet的文章LINQ To Objects and the performance of nested "Where" calls采取:

// Normal LINQ query 
var query = list.Where(x => Condition1(x)) 
       .Where(x => Condition2(x)) 
       .Select(x => Projection1(x)) 
       .Select(y => Projection2(y)); 

// After optimization 
var query = list.WhereSelect(x => Condition1(x) && Condition2(x), 
          x => Projection2(Projection1(x)); 

顺便说一句,你的方法应该返回最具体出现的类型,他们可以。例如,处理T[]数组或List<T>列表的方法在内部通常不应只返回IEnumerable<T>。如果您希望结果是不可变的,请将它换成ReadOnlyCollection<T>

+0

在其他项目中编写用于最大程度重用的类时,如果消费者正在多线程场景中运行,则不会先验地知道该类。多线程环境中的非线程安全类很糟糕。所以你的观点1.似乎表明所有的方法都应该进行急切的评估? – JohnC 2013-03-20 16:34:03

+0

@JohnC我会争辩说,一个可枚举的_knows_的使用者,默认情况下它是_not_线程安全的。在大多数情况下,这不是问题。如果这是一个问题,确保它是线程安全的是消费者的责任。例如通过调用它上面的“ToArray”。如果底层集合已经是一个数组,则什么都不会发生。否则,在这一点上进行评估。 – Virtlink 2013-03-20 16:36:41

+0

参考你的bigquery的例子。First()比bigquery.ToArray()。First()更快,请注意,我在我的问题中声明“假设集合的过滤被认为是完整的(即消费者不太可能会进一步过滤结果) ”。在你的例子中,数组被进一步过滤了第一个元素;不完全是我所要求的场景。 – JohnC 2013-03-20 16:36:47