继续对IEnumerable进行枚举

Ras*_*ond 3 c#

使用yield关键字,我们只能计算中所需的项目数量IEnumerable。我已经建立了一个测试,其中我生成了许多项目,然后又想生成一个项目。我期望的是该函数从其结束处开始,在这种情况下是在10000000迭代中,仅再次迭代到10000001。请检查这段代码:

public static void Main()
{
    var naturalNumbers = GetNaturalNumbers();

    var executionTime = GetExecutionTime(() => naturalNumbers.ElementAt(10000000));
    Console.WriteLine($"Time elapsed: {executionTime}");

    executionTime = GetExecutionTime(() => naturalNumbers.ElementAt(10000001));
    Console.WriteLine($"Time elapsed: {executionTime}");
}

public static IEnumerable<int> GetNaturalNumbers()
{
    Console.WriteLine("Running GetNaturalNumbers() from the beginning");
    for(int value = 0;; value++)
    {
        yield return value;
    }
}

public static System.TimeSpan GetExecutionTime(Action action)
{
    var stopwatch = Stopwatch.StartNew();

    action();

    stopwatch.Stop();
    return stopwatch.Elapsed;
}
Run Code Online (Sandbox Code Playgroud)

输出:

Running GetNaturalNumbers() from the beginning
Time elapsed: 00:00:00.0618548
Running GetNaturalNumbers() from the beginning
Time elapsed: 00:00:00.0562454
Run Code Online (Sandbox Code Playgroud)

第二次调用所花费的时间更少,让我猜测这仅仅是因为处理器优化。该函数从头开始被调用两次。

此输出背后的真正原因是什么?是否可以从我们在第一个通话中结束的位置继续进行迭代?

编辑:

现在我看到我的例子还不够好。假设我们在GetNaturalNumbers()函数中有一个非常复杂且耗时的操作。我期望第二个调用从10000000第th个元素开始枚举,而无需再次计算所有元素。我希望在第二次电话会议中获得显着的性能提升。


另一个例子:

想象一下,一本书有很多页,您不想一次获得所有页面,而只希望获得读者需要的数量。当读者翻页时,我们无需计算所有先前页面就可以获取它。

Pat*_*ick 5

其他所有人似乎都在谈论速度,这似乎并不是您真正的问题。

您认为执行后:

var executionTime = GetExecutionTime(() => naturalNumbers.ElementAt(10000000));

然后执行:

executionTime = GetExecutionTime(() => naturalNumbers.ElementAt(10000001));

应该知道您已经这样做了,10000000因此它应该只执行一次循环迭代。

那根本不是它的工作原理。您的收益回报将缩短循环并返回所需的值,但是这两个语句都是完全独立的,并且将运行:

for(int value = 0;; value++)

两次。

  • 我们都知道它做了两次枚举。这个答案只是对问题背景的重新陈述。“ _此输出背后的真正原因是什么?_”答案=&gt;您没有正确执行基准测试。 (2认同)