我目前正在做一些最後的措施優化,主要是爲了好玩和學習,並發現了一些讓我留下幾個問題的東西。好奇心:爲什麼表達式<...>編譯時運行速度比最小的DynamicMethod快?
首先,問題:
- 當我構造的內存中的方法通過使用DynamicMethod,並使用調試器,是否有任何方式爲我vieweing當踏入生成的彙編代碼,反彙編視圖中的代碼?調試器似乎只是對我整個方法的步驟
- 或者,如果這是不可能的,是否有可能以某種方式將生成的IL代碼作爲程序集保存到磁盤,以便我可以用Reflector檢查它?
- 爲什麼我的簡單加法方法(Int32 + Int32 => Int32)的
Expression<...>
版本比最小的DynamicMethod版本運行得更快?
下面是一個簡短而完整的程序演示。在我的系統,輸出爲:
DynamicMethod: 887 ms
Lambda: 1878 ms
Method: 1969 ms
Expression: 681 ms
我預期的λ和方法調用具有更高的價值,但DynamicMethod的版本是一致慢約30-50%(的變化可能是由於Windows和其他程序)。任何人都知道原因?
這裏的程序:
using System;
using System.Linq.Expressions;
using System.Reflection.Emit;
using System.Diagnostics;
namespace Sandbox
{
public class Program
{
public static void Main(String[] args)
{
DynamicMethod method = new DynamicMethod("TestMethod",
typeof(Int32), new Type[] { typeof(Int32), typeof(Int32) });
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Ret);
Func<Int32, Int32, Int32> f1 =
(Func<Int32, Int32, Int32>)method.CreateDelegate(
typeof(Func<Int32, Int32, Int32>));
Func<Int32, Int32, Int32> f2 = (Int32 a, Int32 b) => a + b;
Func<Int32, Int32, Int32> f3 = Sum;
Expression<Func<Int32, Int32, Int32>> f4x = (a, b) => a + b;
Func<Int32, Int32, Int32> f4 = f4x.Compile();
for (Int32 pass = 1; pass <= 2; pass++)
{
// Pass 1 just runs all the code without writing out anything
// to avoid JIT overhead influencing the results
Time(f1, "DynamicMethod", pass);
Time(f2, "Lambda", pass);
Time(f3, "Method", pass);
Time(f4, "Expression", pass);
}
}
private static void Time(Func<Int32, Int32, Int32> fn,
String name, Int32 pass)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (Int32 index = 0; index <= 100000000; index++)
{
Int32 result = fn(index, 1);
}
sw.Stop();
if (pass == 2)
Debug.WriteLine(name + ": " + sw.ElapsedMilliseconds + " ms");
}
private static Int32 Sum(Int32 a, Int32 b)
{
return a + b;
}
}
}
有趣的問題。使用WinDebug和SOS可以解決這些問題。我發佈了一個類似分析的步驟,我在我的博客中進行了許多個月前的測試,http://blog.barrkel.com/2006/05/clr-tailcall-optimization-or-lack.html – 2009-08-18 23:25:22
我想我應該ping你 - 我發現如何強制JIT而不必調用該方法一次。使用'restrictedSkipVisibility' DynamicMethod構造函數參數。根據上下文(代碼安全性),它可能不可用。 – 2009-08-19 13:43:13
真的很好的問題。首先,對於這種類型的分析,我會使用release/Console - 所以'Debug.WriteLine'看起來不合適;但即使'Console.WriteLine'我的統計是類似的:DynamicMethod:630毫秒Lambda:561毫秒方法:553毫秒錶達式:360毫秒我仍在尋找... – 2009-08-18 21:49:15