使用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个元素开始枚举,而无需再次计算所有元素。我希望在第二次电话会议中获得显着的性能提升。
另一个例子:
想象一下,一本书有很多页,您不想一次获得所有页面,而只希望获得读者需要的数量。当读者翻页时,我们无需计算所有先前页面就可以获取它。
其他所有人似乎都在谈论速度,这似乎并不是您真正的问题。
您认为执行后:
var executionTime = GetExecutionTime(() => naturalNumbers.ElementAt(10000000));
然后执行:
executionTime = GetExecutionTime(() => naturalNumbers.ElementAt(10000001));
应该知道您已经这样做了,10000000因此它应该只执行一次循环迭代。
那根本不是它的工作原理。您的收益回报将缩短循环并返回所需的值,但是这两个语句都是完全独立的,并且将运行:
for(int value = 0;; value++)
两次。