流媒体运营商与延期执行有何不同?

时间:2012-04-05 21:08:51

标签: c# linq

在LINQ Where中是一个流媒体运营商。 Where-as OrderByDescending是非流媒体运营商。 AFAIK,流媒体运营商只收集下一个必要的项目。非流式运算符一次评估整个数据流。

我没有看到定义流媒体运营商的相关性。对我来说,延期执行是多余的。以我编写自定义扩展并使用where运算符和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都需要评估每个元素,以确定哪些元素符合条件。它产量的事实似乎只是变得相关,因为运营商获得了延期执行。

那么,流媒体运营商的重要性是什么?

3 个答案:

答案 0 :(得分:14)

有两个方面:速度和记忆。

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

// 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。此外,一次只能将一个值加载到内存中,因此内存占用非常小。

在第二个示例中,OrderByDescending不是流式传输,所以当Take取出第一个项目时,通过Where过滤器的整个结果必须放在内存中进行排序。这可能需要很长时间并产生大量内存。

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

// 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);

答案 1 :(得分:2)

  

它产量的事实似乎只是变得相关,因为   运营商获得延期执行。

     

那么,流媒体运营商的重要性是什么?

即。你无法使用缓冲/非流扩展方法处理无限序列 - 虽然你可以“运行”这样的序列(直到你中止),只使用流扩展方法就好了。

以此方法为例:

public IEnumerable<int> GetNumbers(int start)
{
    int num = start;

    while(true)
    {
        yield return num;
        num++;
    }
}

您可以正常使用Where

foreach (var num in GetNumbers(0).Where(x => x % 2 == 0))
{
    Console.WriteLine(num);
}

OrderBy()在这种情况下不起作用,因为它必须在发出单个数字之前详尽地枚举结果。

答案 2 :(得分:2)

只是要明确;在你提到的情况下,没有任何优势,因为订单在任何情况下吸收了整个事物。然而,有时会使用流媒体的优势(其他答案/评论已经给出了示例),因此所有LINQ运营商都将发送到最佳能力。订购流尽可能多,这恰好不是很多。流非常有效。