【问题标题】:IEnumerable<T> result from a method and deferred executionIEnumerable<T> 来自方法和延迟执行的结果
【发布时间】:2013-03-20 16:15:28
【问题描述】:

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

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

省略无限序列等特殊情况(例如斐波那契)并假设集合的过滤被认为是完整的(即消费者不太可能进一步过滤结果),这将被认为是“最佳方法" 当从一个方法返回一个 IEnumerable 的集合时——它应该已经被评估还是延迟?

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

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

【问题讨论】:

    标签: multithreading linq deferred-execution


    【解决方案1】:

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

    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&lt;T&gt; 列表的方法通常不应只返回IEnumerable&lt;T&gt;。如果您希望结果不可变,请将其包装在 ReadOnlyCollection&lt;T&gt; 中。

    【讨论】:

    • 在编写类以在其他项目中最大程度地重用时,如果消费者在多线程场景中操作,则先验是未知的。多线程环境中的非线程安全类是不好的。所以你的观点 1. 似乎表明所有方法都应该执行热切评估?
    • @JohnC 我认为可枚举的消费者知道默认情况下它是线程安全的。在大多数用例中,这不是问题。如果这是一个问题,消费者有责任确保它是线程安全的。例如通过调用ToArray 就可以了。如果底层集合已经是一个数组,则什么也不会发生。否则,将在该点进行评估。
    • 参考您的 bigquery.First() 比 bigquery.ToArray().First() 更快的示例,请注意我在问题中确实说明了“假设集合的过滤被认为是完整的(即,消费者不太可能进一步过滤结果)”。在您的示例中,数组被进一步过滤为第一个元素;不完全是我要求的场景。
    • 好的,我接受你关于消费者负责确保线程安全的论点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-17
    • 2013-01-12
    • 1970-01-01
    • 1970-01-01
    • 2019-05-08
    相关资源
    最近更新 更多