gpt4 book ai didi

c# - 为什么 Enumerable.Range 比直接 yield 循环更快?

转载 作者:可可西里 更新时间:2023-11-01 08:37:31 30 4
gpt4 key购买 nike

下面的代码正在检查执行相同解决方案的三种不同方法的性能。

    public static void Main(string[] args)
{
// for loop
{
Stopwatch sw = Stopwatch.StartNew();

int accumulator = 0;
for (int i = 1; i <= 100000000; ++i)
{
accumulator += i;
}

sw.Stop();

Console.WriteLine("time = {0}; result = {1}", sw.ElapsedMilliseconds, accumulator);
}

//Enumerable.Range
{
Stopwatch sw = Stopwatch.StartNew();

var ret = Enumerable.Range(1, 100000000).Aggregate(0, (accumulator, n) => accumulator + n);

sw.Stop();
Console.WriteLine("time = {0}; result = {1}", sw.ElapsedMilliseconds, ret);
}

//self-made IEnumerable<int>
{
Stopwatch sw = Stopwatch.StartNew();

var ret = GetIntRange(1, 100000000).Aggregate(0, (accumulator, n) => accumulator + n);

sw.Stop();
Console.WriteLine("time = {0}; result = {1}", sw.ElapsedMilliseconds, ret);
}
}

private static IEnumerable<int> GetIntRange(int start, int count)
{
int end = start + count;

for (int i = start; i < end; ++i)
{
yield return i;
}
}
}

结果是:

time = 306; result = 987459712
time = 1301; result = 987459712
time = 2860; result = 987459712

“for 循环”比其他两种解决方案更快也就不足为奇了,因为 Enumerable.Aggregate 需要更多的方法调用。然而,令我惊讶的是“Enumerable.Range”比“自制的IEnumerable”更快。我认为 Enumerable.Range 会比简单的 GetIntRange 方法有更多的开销。

这可能是什么原因?

最佳答案

为什么 Enumerable.Range 应该比您自制的 GetIntRange 慢?事实上,如果 Enumerable.Range 定义为

public static class Enumerable {
public static IEnumerable<int> Range(int start, int count) {
var end = start + count;
for(var current = start; current < end; ++current) {
yield return current;
}
}
}

那么它应该和你自制的 GetIntRange 一样快。这实际上是 Enumerable.Range 的引用实现,编译器或程序员没有任何技巧。

您可能希望将您的 GetIntRangeSystem.Linq.Enumerable.Range 与以下实现进行比较(当然,正如 Rob 指出的那样,在 Release模式下编译) .相对于编译器从迭代器 block 生成的内容,此实现可能会略有优化。

public static class Enumerable {
public static IEnumerable<int> Range(int start, int count) {
return new RangeEnumerable(start, count);
}
private class RangeEnumerable : IEnumerable<int> {
private int _Start;
private int _Count;
public RangeEnumerable(int start, int count) {
_Start = start;
_Count = count;
}
public virtual IEnumerator<int> GetEnumerator() {
return new RangeEnumerator(_Start, _Count);
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
private class RangeEnumerator : IEnumerator<int> {
private int _Current;
private int _End;
public RangeEnumerator(int start, int count) {
_Current = start - 1;
_End = start + count;
}
public virtual void Dispose() {
_Current = _End;
}
public virtual void Reset() {
throw new NotImplementedException();
}
public virtual bool MoveNext() {
++_Current;
return _Current < _End;
}
public virtual int Current { get { return _Current; } }
object IEnumerator.Current { get { return Current; } }
}
}

关于c# - 为什么 Enumerable.Range 比直接 yield 循环更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/408452/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com