IEnumerable <t>来自方法和延迟执行的结果</t>

时间:2013-03-20 16:15:29

标签: multithreading linq deferred-execution

我理解LINQ中的延迟执行,如下所述: What are the benefits of a Deferred Execution in LINQ?

但是,延迟执行可能会导致错误,尤其是在多线程场景中,例如。对锁外的共享集合执行的评估。当一个返回延迟评估的方法嵌套了几个深层的方法层时,它会变得非常困难(至少对我而言)要记住或跟踪我是否适当锁定。

忽略无限序列(例如Fibonacci)等特殊情况并假设对集合进行过滤被认为是完整的(即,消费者不太可能进一步过滤结果),这将被视为“最佳方法” “当从方法返回IEnumerable的集合时 - 它是否已经被评估或推迟?

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

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

1 个答案:

答案 0 :(得分:2)

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

  1. 您需要在多线程环境中使用它。你应该把它变成一个列表或数组。
  2. 您希望随机访问可枚举项。你应该把它变成一个列表或数组。
  3. 您希望控制何时进行评估(例如,如果价格昂贵)。
  4. 在其他时候,您应该让它使用延迟执行。这会将评估推迟到实际需要的程度,并且可能会更快,具体取决于您应用的过滤器。例如,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>中。