Hi, today I prepared a compilation of the delegate with Roslyn CTP, June 2012 version. It is not a big deal because I am trying to compile delegates more efficiently. But I want to share with you the results of my experiments with it. I think that compiler as a service has great potential. I will present some code as my favorite template – Console Application. And later, I will show you a CompiledDelegate<Tin, Tout> class. The class is not finished yet, and I am still working on it because of the possibility of increased performance. You probably know that for example lambda exception like below
arg => arg * 2
is for example type of Expression<Func<int, int>> and that Expression<T> is great because you can invoke on it Compile method and speed up your invocation. That is part of LINQ. On the other hand, we have, for example, something like below
arg => { return arg * 2; }
and because of curly brackets we have something very similar that works exactly the same except it is slower because type of it is for example a delegate Func<int, int>. No Expression Tree is possible to create on it like in the first example. We cannot compile it and speed it up at the same moment. So, I will try to prepare something that maybe will be faster. We will see. Sorry, it is not the most beautiful code, but it was created for measurement only. It looks like below.
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Linq.Expressions; using System.Text; namespace CompiledDelegateSandbox { class Program { static void Main(string[] args) { Func<int , int> funcA = cA => { var icA = 0; for (var i = 1; i < = cA; ++i) { var jcA = 0; for (var j = 1; j <= cA; ++j) { jcA += 1; } icA += 1; } return icA; }; Expression<Func<int, int>> f = a => 1; Func<int , int> funcB = new CompiledDelegate<Func<int , int>>( @"funcB", @" int funcB(int cB) { var icB = 0; for (var i = 1; i < = cB; ++i) { var jcB = 0; for (var j = 1; j <= cB; ++j) { jcB += 1; } icB += 1; } return icB; } " ).Delegate; var c = 10000; var meter = new Stopwatch(); meter.Start(); var rA = 0; for(var i = 0; i < 5; ++i) rA = funcA(c); meter.Stop(); var resultA = meter.ElapsedMilliseconds; meter.Reset(); meter.Start(); var rB = 0; for(var i = 0; i < 5; ++i) rB = funcB(c); meter.Stop(); var resultB = meter.ElapsedMilliseconds; Console.WriteLine("Results a({1}): {0} ms, b({3}): {2} ms.", resultA, rA, resultB, rB); Console.WriteLine("Press any key to close..."); Console.ReadKey(); } } }
You maybe wonder about the result, but first I will show you CompiledDelegate<Tin,Tout> class implementation.
using Roslyn.Scripting; using Roslyn.Scripting.CSharp; using System; using System.Linq.Expressions; namespace CompiledDelegateSandbox { public class CompiledDelegate<Tin , Tout> { private readonly Func<Tin , Tout> _compiled; public CompiledDelegate(string methodName, string code) { var scriptEngine = new ScriptEngine( references: new[] { typeof(ScriptEngine).Assembly // SOON in ROSLYN //,typeof(Expression).Assembly }, importedNamespaces: new string[] { "System" // SOON in ROSLYN //,"System.Linq.Expressions" } ); var session = Session.Create(); var func = "func"; scriptEngine.Execute(code, session); // SOON in ROSLYN //var compiledCode = // string.Format("new Expression<func <{0},{1}>> {2} = arg => {3}(arg); {2}.Compile(); {2}", // typeof(Tin).Name, typeof(Tout).Name, func, methodName); var compiledCode = string.Format("new Func<{0},{1}>(arg => {2}(arg))", typeof(Tin).Name, typeof(Tout).Name, methodName); var compiled = scriptEngine.CompileSubmission<Func <Tin, Tout>>(compiledCode, session); Expression<Func <Tin, Tout>> expression = arg => compiled.Execute().Invoke(arg); _compiled = expression.Compile(); } public Func<Tin , Tout> Delegate { get { return _compiled; } } } }
I hate comments, you know, but this time I used them to show you what will probably soon be possible with the Roslyn project. It may be possible in the future to compile an Execution Tree because the following code
arg => method(arg)
is for example type of our favorite Expression<Func<int, int>> that can be compiled and speed up. I think that my implementation of this CompiledDelegate<Tin, Tout> class is very light, and you probably can understand it all. If not, let me know in the comments. And last but not least, I will show you an output of the performance test presented before. It works like this.
Results a(10000): 287 ms, b(10000): 433 ms. Press any key to close...
It is not very fast, so I was a little disappointed, but I think it can be interesting for you somehow. To try these examples, you need Visual Studio 2010/2012 SDK and Roslyn CTP June 2012. I hope you enjoy this entry.
P ;).
Why do U think that compiled expression tree is faster than the same delegate declared directly in code? It’s not true.
http://stackoverflow.com/questions/3392388/why-delegates-generated-dynamically-from-expressions-are-slower-than-hard-coded
I am not agree, here is a prove:
An output: