流式操作符与延迟执行有何不同?

2024-02-18

In LINQ Where是一个流媒体运营商。然而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需要评估每个元素以确定哪些元素满足条件。它产生的事实似乎只是因为操作符获得了延迟执行而变得相关。

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


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

当您使用类似的方法时,速度方面会变得更加明显.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,之前您只会得到 1 到 10 的值Take停止评估。此外,一次仅将一个值加载到内存中,因此内存占用非常小。

在第二个例子中,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);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

流式操作符与延迟执行有何不同? 的相关文章

随机推荐