首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >流运算符与延迟执行有何不同?

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

Stack Overflow用户
提问于 2012-04-06 05:08:51
回答 3查看 2K关注 0票数 9

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

我看不出定义流媒体运营商的相关性。对我来说,延迟执行是多余的。以我编写了一个自定义扩展并使用where操作符和orderby使用它的示例为例。

代码语言:javascript
复制
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都需要评估每个元素,以确定哪些元素满足条件。它产生的事实似乎只有在运算符获得延迟执行时才变得相关。

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

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-04-06 05:11:46

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

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

代码语言:javascript
复制
// 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,内存问题也是很重要的。例如:

代码语言:javascript
复制
// 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);
票数 15
EN

Stack Overflow用户

发布于 2012-04-06 05:12:25

它产生的事实似乎只会变得相关,因为运算符获得了延迟执行。

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

也就是说,你不能使用缓冲/非流扩展方法来处理无限序列-而你可以只使用流扩展方法来“运行”这样的序列(直到你中止)。

以下面的方法为例:

代码语言:javascript
复制
public IEnumerable<int> GetNumbers(int start)
{
    int num = start;

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

您可以很好地使用Where

代码语言:javascript
复制
foreach (var num in GetNumbers(0).Where(x => x % 2 == 0))
{
    Console.WriteLine(num);
}

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

票数 2
EN

Stack Overflow用户

发布于 2012-04-06 05:26:29

明确地说,在你提到的情况下,在哪里流是没有好处的,因为orderby无论如何都会吸走整个东西。然而,有时会使用流的优势(其他答案/评论已经给出了例子),所以所有的LINQ操作员都会尽其所能将流到。Orderby流传输尽可能多地使用,但恰好不是很多。那里的流水非常有效。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10036033

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档