流运算符与延迟执行有何不同

流运算符与延迟执行有何不同

本文介绍了流运算符与延迟执行有何不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在LINQ中,Where是流运算符.其中-OrderByDescending是非流运算符. AFAIK,流运算符仅收集必要的下一项.非流运算符可一次评估整个数据流.

In LINQ Where is a streaming operator. Where-as OrderByDescending is a non-streaming operator. AFAIK, a streaming operator only gathers the next item that is necessary. A non-streaming operator evaluates the entire data stream at once.

我看不到定义流运算符的相关性.对我来说,延迟执行是多余的.以我编写自定义扩展并使用where运算符and和orderby消费它的示例为例.

I fail to see the relevance of defining a Streaming Operator. To me, it is redundant with Deferred Execution. Take the example where I have written a custom extension and consumed it using the where operator and and orderby.

public static class ExtensionStuff
{
    public static IEnumerable<int> Where(this IEnumerable<int> sequence, Func<int, bool> predicate)
    {
        foreach (int i in sequence)
        {
            if (predicate(i))
            {
                yield return i;
            }
        }
    }
}

    public static void Main()
    {
        TestLinq3();
    }

    private static void TestLinq3()
    {
        int[] items = { 1, 2, 3,4 };

        var selected = items.Where(i => i < 3)
                            .OrderByDescending(i => i);

        Write(selected);
    }



    private static void Write(IEnumerable<int> selected)
    {
        foreach(var i in selected)
            Console.WriteLine(i);
    }

无论哪种情况,Where都需要评估每个元素,以确定哪些元素满足条件.它产生的事实似乎仅是相关的,因为操作员获得了延迟执行.

In either case, Where needs to evaluate each element in order to determine which elements meet the condition. The fact that it yields seems to only become relevant because the operator gains deferred execution.

那么,流运算符的重要性是什么?

So, what is the importance of Streaming Operators?

推荐答案

有两个方面:速度和内存.

There are two aspects: speed and memory.

当使用.Take()之类的方法仅消耗原始结果集的一部分时,速度方面会变得更加明显.

The speed aspect becomes more apparent when you use a method like .Take() to only consume a portion of the original result set.

// Consumes ten elements, yields 5 results.
Enumerable.Range(1, 1000000).Where(i => i % 2 == 0)
    .Take(5)
    .ToList();

// Consumes one million elements, yields 5 results.
Enumerable.Range(1, 1000000).Where(i => i % 2 == 0)
    .OrderByDescending(i => i)
    .Take(5)
    .ToList();

由于第一个示例在调用Take之前仅使用流运算符,因此在Take停止求值之前,您只能得到1到10的值.此外,一次只将一个值加载到内存中,因此您的内存占用非常小.

Because the first example uses only streaming operators before the call to Take, you only end up yielding values 1 through 10 before Take stops evaluating. Furthermore, only one value is loaded into memory at a time, so you have a very small memory footprint.

在第二个示例中,OrderByDescending没有流式传输,因此在Take拉出第一项时,必须将通过Where过滤器传递的整个结果存储在内存中以进行排序.这可能需要很长时间,并且会占用大量内存.

In the second example, OrderByDescending is not streaming, so the moment Take pulls the first item, the entire result that's passed through the Where filter has to be placed in memory for sorting. This could take a long time and produce a big memory footprint.

即使您没有使用Take,内存问题也可能很重要.例如:

Even if you weren't using Take, the memory issue can be important. For example:

// Puts half a million elements in memory, sorts, then outputs them.
var numbers = Enumerable.Range(1, 1000000).Where(i => i % 2 == 0)
    .OrderByDescending(i => i);
foreach(var number in numbers) Console.WriteLine(number);

// Puts one element in memory at a time.
var numbers = Enumerable.Range(1, 1000000).Where(i => i % 2 == 0);
foreach(var number in numbers) Console.WriteLine(number);

这篇关于流运算符与延迟执行有何不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-16 00:49