I have a simple scenario, where i am trying to test the performance of a expression compiled tree on an list of stock objects. Below is the code
The performance of expression compiled tree is 5x slower than static lambda call. I am not sure whether this is a standard performance one can expect with expression compiled tree. Would appreciate any insight.
LambdaExpression();
List<Stock> stocks = new List<Stock>();
for (int ctr = 0; ctr <= 5000000; ctr++)
{
Stock stk1 = new Stock() { Price = ctr, Symbol = "A", CloseDate = DateTime.Now, FaceValue = ctr } ;
stocks.Add(stk1);
}
CompileTimeLamda(a);
DynamicLambda(a);
public static void LambdaExpression()
{
ParameterExpression CS1 = Expression.Parameter(typeof(Stock), "d");
var line1 = Expression.Equal(Expression.Property(CS1, typeof(Stock).GetProperty("Symbol")), Expression.Constant("MSFT", typeof(string)));
var line2 = Expression.GreaterThan(Expression.Property(Expression.Property(CS1, typeof(Stock).GetProperty("CloseDate")),typeof(DateTime).GetProperty("Millisecond")),
Expression.Constant(0, typeof(int)));
var line3 = Expression.GreaterThan(Expression.Property(CS1, typeof(Stock).GetProperty("Price")), Expression.Constant((double)0, typeof(double)));
var line4 = Expression.And(line1,line2);
var line5 = Expression.OrElse(line4, line3);
func = Expression.Lambda<Func<Stock, bool>>(line5, new ParameterExpression[] { CS1 } ).Compile();
}
public static void DynamicLambda(List<Stock> stks)
{
Stopwatch watch = new Stopwatch();
watch.Start();
foreach (var d in stks)
{
func(d);
}
watch.Stop();
Console.WriteLine("Dynamic Lambda :" + watch.ElapsedMilliseconds);
}
public static void CompileTimeLamda(List<Stock> stks)
{
Stopwatch watch = new Stopwatch();
watch.Start();
foreach (var d in stks)
{
if (d.Symbol == "MSFT" && d.CloseDate.Millisecond > 0 ||
(d.Price) > 0) ;
}
watch.Stop();
Console.WriteLine("Compile Time Lamda " +watch.ElapsedMilliseconds);
}
The difference has to do with the compiler having more information and spending more effort on optimizing the code if you compile it at compile time, rather than at runtime… Also, using a lambda, you have a more “flexible” program (you can choose the lambda at run time). That comes at the cost of
an extra function call, and losing a lot of potential optimizations.
To make a more “fair” comparison, you can compare a static lambda vs a dynamic lambda using something like:
instead of the hardcoded code..
There you’ll also find a difference, but a slightly smaller one… The difference is for the same reason (more optimization)… You can decrease the difference by optimizing your lambda by hand (although that isn’t always possible, since the compiler can create valid CLI code that can’t be created manually with a lambda).
But for example, if you change your dynamic lambda from:
to:
You’ll see how the lambda performs between 1x and 2x of your original compiled code.