考慮下面的代碼:的ILGenerator方法內聯
using System;
using System.Reflection.Emit;
using System.Diagnostics;
using System.Reflection;
namespace ConsoleApplication1
{
class A
{
public int Do(int n)
{
return n;
}
}
public delegate int DoDelegate();
class Program
{
public static void Main(string[] args)
{
A a = new A();
Stopwatch stopwatch = Stopwatch.StartNew();
int s = 0;
for (int i = 0; i < 100000000; i++)
{
s += a.Do(i);
}
Console.WriteLine(stopwatch.ElapsedMilliseconds);
Console.WriteLine(s);
DynamicMethod dm = new DynamicMethod("Echo", typeof(int), new Type[] { typeof(int) }, true);
ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ret);
DynamicMethod dm2 = new DynamicMethod("Test", typeof(int), new Type[0]);
il = dm2.GetILGenerator();
Label loopStart = il.DefineLabel();
Label loopCond = il.DefineLabel();
il.DeclareLocal(typeof(int)); // i
il.DeclareLocal(typeof(int)); // s
// s = 0;
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Stloc_1);
// i = 0;
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Br_S, loopCond);
il.MarkLabel(loopStart);
// s += Echo(i);
il.Emit(OpCodes.Ldloc_1); // Load s
il.Emit(OpCodes.Ldloc_0); // Load i
il.Emit(OpCodes.Call, dm); // Call echo method
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Stloc_1);
// i++
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Stloc_0);
il.MarkLabel(loopCond);
// Check for loop condition
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ldc_I4, 100000000);
il.Emit(OpCodes.Blt_S, loopStart);
il.Emit(OpCodes.Ldloc_1);
il.Emit(OpCodes.Ret);
DoDelegate doDel = (DoDelegate)dm2.CreateDelegate(typeof(DoDelegate));
s = doDel.Invoke(); // Dummy run to force JIT
stopwatch = Stopwatch.StartNew();
s = doDel.Invoke();
Console.WriteLine(stopwatch.ElapsedMilliseconds);
Console.WriteLine(s);
}
}
}
電話方式,否則被內聯。循環在約40毫秒內完成。例如,如果我將Do設爲虛擬函數,則它不會被內聯,並且循環在240 ms內完成。到現在爲止還挺好。當我使用ILGenerator生成Do方法(Echo),然後使用與給定主方法相同的循環生成DynamicMethod時,調用Echo方法永遠不會內聯,並且循環完成需要約240 ms。 MSIL代碼是正確的,因爲它返回與C#代碼相同的結果。我確信方法內聯是由JIT完成的,所以我沒有理由不內聯Echo方法。
有人知道爲什麼這個簡單的方法不會被JIT內聯。
您還正在生成調用動態生成的Do()方法的代碼,還是編譯時已知的代碼? – 2011-12-31 00:12:48
您能否包含使用ILGenerator的完整代碼示例?而且,爲了確保:您是否在發佈版本**下進行測試,而沒有附加調試器? – 2011-12-31 05:37:56
我已重新編輯帖子,給出測試應用程序的完整代碼。我使用發佈版本並在沒有調試器的情況下運行它。 C#for循環內聯方法調用,運行速度明顯快於IL for循環。 – user102808 2011-12-31 09:22:26