The code below is checking performance of three different ways to do same solution.
public static void Main(string[] args)
{
// for loop
A slight difference in the Reflector output (as well as the argument check and extra level of internalisation definitely not relevant here). The essential code is more like:
public static IEnumerable Range(int start, int count) {
for(int current = 0; current < count; ++current) {
yield return start + current;
}
}
That is, instead of another local variable, they apply an extra addition for every yield.
I have tried to benchmark this, but I can't stop enough external processes to get understandable results. I also tried each test twice to ignore the effects of the JIT compiler, but even that has 'interesting' results.
Here's a sample of my results:
Run 0: time = 4149; result = 405000000450000000 time = 25645; result = 405000000450000000 time = 39229; result = 405000000450000000 time = 29872; result = 405000000450000000 time = 4277; result = 405000000450000000 time = 26878; result = 405000000450000000 time = 26333; result = 405000000450000000 time = 26684; result = 405000000450000000 Run 1: time = 4063; result = 405000000450000000 time = 22714; result = 405000000450000000 time = 34744; result = 405000000450000000 time = 26954; result = 405000000450000000 time = 4033; result = 405000000450000000 time = 26657; result = 405000000450000000 time = 25855; result = 405000000450000000 time = 25031; result = 405000000450000000 Run 2: time = 4021; result = 405000000450000000 time = 21815; result = 405000000450000000 time = 34304; result = 405000000450000000 time = 32040; result = 405000000450000000 time = 3993; result = 405000000450000000 time = 24779; result = 405000000450000000 time = 29275; result = 405000000450000000 time = 32254; result = 405000000450000000
and the code
using System;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
namespace RangeTests
{
class TestRange
{
public static void Main(string[] args)
{
for(int l = 1; l <= 2; ++l)
{
const int N = 900000000;
System.GC.Collect(2);
// for loop
{
Stopwatch sw = Stopwatch.StartNew();
long accumulator = 0;
for (int i = 1; i <= N; ++i)
{
accumulator += i;
}
sw.Stop();
Console.WriteLine("time = {0}; result = {1}", sw.ElapsedMilliseconds, accumulator);
}
System.GC.Collect(2);
//Enumerable.Range
{
Stopwatch sw = Stopwatch.StartNew();
var ret = Enumerable.Range(1, N).Aggregate(0, (long accumulator,int n) => accumulator + n);
sw.Stop();
Console.WriteLine("time = {0}; result = {1}", sw.ElapsedMilliseconds, ret);
}
System.GC.Collect(2);
//self-made IEnumerable
{
Stopwatch sw = Stopwatch.StartNew();
var ret = GetIntRange(1, N).Aggregate(0, (long accumulator,int n) => accumulator + n);
sw.Stop();
Console.WriteLine("time = {0}; result = {1}", sw.ElapsedMilliseconds, ret);
}
System.GC.Collect(2);
//self-made adjusted IEnumerable
{
Stopwatch sw = Stopwatch.StartNew();
var ret = GetRange(1, N).Aggregate(0, (long accumulator,int n) => accumulator + n);
sw.Stop();
Console.WriteLine("time = {0}; result = {1}", sw.ElapsedMilliseconds, ret);
}
System.GC.Collect(2);
Console.WriteLine();
} }
private static IEnumerable GetIntRange(int start, int count)
{
int end = start + count;
for (int i = start; i < end; ++i)
{
yield return i;
}
}
private static IEnumerable GetRange(int start, int count)
{
for (int i = 0; i < count; ++i)
{
yield return start + i;
}
}
} }
compiled with
csc.exe -optimize+ -debug- RangeTests.cs