2008-08-21

Delegates - Late Bound VS Expression

With the new Expressions .NET 3.5, is there any reason to use a late bound delegate?
Lets put it to the test.

lateboundvsexpression

Milliseconds/number of iterations.  (less is better.)

Expressions have almost constant time, while LateBound suffers under many iterations.

And the test code.

   1: using System;
   2: using System.Diagnostics;
   3: using System.Linq.Expressions;
   4: using System.Reflection;
   5: using NUnit.Framework;
   6:  
   7: namespace Sample
   8: {
   9:     [TestFixture]
  10:     public class LateBoundVSExpressionCall
  11:     {
  12:         [Test]
  13:         public void TestLateBound()
  14:         {
  15:             object instance = new object();
  16:             Stopwatch stopwatch = Stopwatch.StartNew();
  17:             MethodInfo methodInfo = typeof(object).GetMethod("ToString");
  18:             for (int i = 0; i < 1000000; i++)
  19:             {
  20:                 methodInfo.Invoke(instance, null);
  21:             }
  22:             stopwatch.Stop();
  23:             Trace.WriteLine("LateBound: " + stopwatch.ElapsedMilliseconds + " milliseconds");
  24:         }
  25:  
  26:         [Test]
  27:         public void TestExpression()
  28:         {
  29:             object instance = new object();
  30:             Stopwatch stopwatch = Stopwatch.StartNew();
  31:             MethodInfo methodInfo = typeof(object).GetMethod("ToString");
  32:             ConstantExpression constantExpression = Expression.Constant(instance);
  33:             MethodCallExpression methodCallExpression = Expression.Call(constantExpression, methodInfo);
  34:             Func toString = Expression.Lambda>(methodCallExpression).Compile();
  35:             for (int i = 0; i < 1000000; i++)
  36:             {
  37:                 toString();
  38:             }
  39:             stopwatch.Stop();
  40:             Trace.WriteLine("ExpressionCall: " + stopwatch.ElapsedMilliseconds + " milliseconds");
  41:         }
  42:     }
  43: }

So with just a few extra calls to Expression, we get run time il, that performs a lot better.

3 comments:

Omer said...

As your benchmarks have shown, the improvement comes only after you have called the same method well over 10,000 times and even then, the improvement was small.
This is an extreme scenario. I can't imagine anyone doing 10,000 reflection calls in a daily situation and there's a huge overhead if you do a small number of calls.

Morten Lyhr said...

But then again if it is not done many times, then there is no need to optimize?

So you might aswell use the Expression?

Omer said...

If it is not done many times, I would rather pay the penalty of the reflection calls, rather than pay the one time penalty of expressions, which is much larger than the whole penalty inflicted by reflection.

For example: Expression takes 0.5 sec to create and then calls are 0 sec each. Reflection takes 0.001 sec for each call. If I have 100 calls, Expressions will take 0.5 second and Reflection will take 0.1 second. I would then choose Reflection.

Here it's even more important to understand - since they equal out after over 10,000 calls, not 500 like in my example.