Consider the following code...
In my tests for a RELEASE (not debug!) x86 build on a Windows 7 x64 PC (Intel i7 3GHz) I obtained the following results:
CreateSequence() with new() took 00:00:00.9158071
CreateSequence() with creator() took 00:00:00.1383482
CreateSequence() with new() took 00:00:00.9198317
CreateSequence() with creator() took 00:00:00.1372920
CreateSequence() with new() took 00:00:00.9340462
CreateSequence() with creator() took 00:00:00.1447375
CreateSequence() with new() took 00:00:00.9344077
CreateSequence() with creator() took 00:00:00.1365162
It seems that using a Func<> to define a delegate to create new objects is more than 6 times faster than calling "new T()" directly.
I find this slightly unexpected... I guess it's because of some inlining done by the Jitter, but I'd have thought that it would have been able to optimize the "new T()" just as well.
Does anyone have an explanation for this?
Maybe I'm making some mistake. (I've considered the effect the garbage collector might have, but rearranging the code and adding GC.Collect() and so on doesn't change the results significantly).
Anyway, here's the code:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ConsoleApplication6
{
class Program
{
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
int repeats = 100;
int count = 100000;
for (int outer = 0; outer < 4; ++outer)
{
sw.Restart();
for (int inner = 0; inner < repeats; ++inner)
{
CreateSequence<object>(count).Count();
}
Console.WriteLine("CreateSequence() with new() took " + sw.Elapsed);
sw.Restart();
for (int inner = 0; inner < repeats; ++inner)
{
CreateSequence(count, () => new object()).Count();
}
Console.WriteLine("CreateSequence() with creator() took " + sw.Elapsed);
Console.WriteLine();
}
}
public static IEnumerable<T> CreateSequence<T>(int n) where T: new()
{
for (int i = 0; i < n; ++i)
{
yield return new T();
}
}
public static IEnumerable<T> CreateSequence<T>(int n, Func<T> creator)
{
for (int i = 0; i < n; ++i)
{
yield return creator();
}
}
}
}
The new()
constraint only ensures that the type passed in has a parameterless constructor. If you actually call new T()
(or whatever your type argument's name is), it actually does this:
Activator.CreateInstance<T>();
Which, at its core, uses reflection.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With