March 2008 Entries

Creating Objects - Round 3


Ayende has been discussing the different ways of actually creating objects in .NET and the perf cost associated to each of them.  I thought I'd add to the mix one more method, using the DLR.  I've talked to several people who have identified concerns with the speed of the DLR so I found the results rather interesting.  The context is still the same, identify the time it takes to construct one million Created instances.
The delegate:
delegate Created CreateInstance(int num, string name);
The structure:
public class Created
  public int Num;
  public string Name;
  public Created(int num, string name)
    Num = num;
    Name = name;
Grab the constructor:
ConstructorInfo ci = typeof (Created).GetConstructors()[0];
Define the parameters to be passed to the constructor (relative to the code block we are about to define):
Variable num = Variable.Parameter(SymbolTable.StringToId("num"), typeof (int));
Variable name = Variable.Parameter(SymbolTable.StringToId("name"), typeof (string));
Build a code block with the Ast factories for building expressions (this builds our function for creating new Created instances with our parameters):
CodeBlock block = Ast.CodeBlock("CreateInstance", typeof (Created),
  Ast.Return(Ast.New(ci, new Expression[] {Ast.Read(num), Ast.Read(name)})),
  new Variable[] {num, name}, new Variable[0]);
Compile our block:
CreateInstance create_instance = TreeCompiler.CompileBlock<CreateInstance>(block); 
Invoke the compiled instance:
int iterations = 1000000;
Stopwatch watch = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
  create_instance(i, i.ToString());
The results are rather impressive, the run time on my machine was 00:00:00.2737688.  It looks like creating objects within the DLR via a dynamic code block is pretty cheap.  I've included the source here if you want to run the example.  The DLR bits are based off a release from CodePlex two days ago, the RubyForge bits are much older and will not compile with the above code.  Thoughts?