我刚刚构建了动态方法 - 见下文(感谢 SO 用户)。看起来,Func 作为一种动态方法创建,IL 注入比 lambda 慢 2 倍。
任何人都知道为什么?
(编辑:这是在 VS2010 中作为 Release x64 构建的。请从控制台而不是从 Visual Studio F5 内部运行它。)
class Program
{
static void Main(string[] args)
{
var mul1 = IL_EmbedConst(5);
var res = mul1(4);
Console.WriteLine(res);
var mul2 = EmbedConstFunc(5);
res = mul2(4);
Console.WriteLine(res);
double d, acc = 0;
Stopwatch sw = new Stopwatch();
for (int k = 0; k < 10; k++)
{
long time1;
sw.Restart();
for (int i = 0; i < 10000000; i++)
{
d = mul2(i);
acc += d;
}
sw.Stop();
time1 = sw.ElapsedMilliseconds;
sw.Restart();
for (int i = 0; i < 10000000; i++)
{
d = mul1(i);
acc += d;
}
sw.Stop();
Console.WriteLine("{0,6} {1,6}", time1, sw.ElapsedMilliseconds);
}
Console.WriteLine("\n{0}...\n", acc);
Console.ReadLine();
}
static Func<int, int> IL_EmbedConst(int b)
{
var method = new DynamicMethod("EmbedConst", typeof(int), new[] { typeof(int) } );
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4, b);
il.Emit(OpCodes.Mul);
il.Emit(OpCodes.Ret);
return (Func<int, int>)method.CreateDelegate(typeof(Func<int, int>));
}
static Func<int, int> EmbedConstFunc(int b)
{
return a => a * b;
}
}
这是输出(对于 i7 920)
20
20
25 51
25 51
24 51
24 51
24 51
25 51
25 51
25 51
24 51
24 51
4.9999995E+15...
==================================================== ===========================
编辑 编辑 编辑 编辑
这是dhtorpe是正确的证明——更复杂的 lambda 将失去其优势。证明它的代码(这表明 Lambda与 IL 注入具有完全相同的性能):
class Program
{
static void Main(string[] args)
{
var mul1 = IL_EmbedConst(5);
double res = mul1(4,6);
Console.WriteLine(res);
var mul2 = EmbedConstFunc(5);
res = mul2(4,6);
Console.WriteLine(res);
double d, acc = 0;
Stopwatch sw = new Stopwatch();
for (int k = 0; k < 10; k++)
{
long time1;
sw.Restart();
for (int i = 0; i < 10000000; i++)
{
d = mul2(i, i+1);
acc += d;
}
sw.Stop();
time1 = sw.ElapsedMilliseconds;
sw.Restart();
for (int i = 0; i < 10000000; i++)
{
d = mul1(i, i + 1);
acc += d;
}
sw.Stop();
Console.WriteLine("{0,6} {1,6}", time1, sw.ElapsedMilliseconds);
}
Console.WriteLine("\n{0}...\n", acc);
Console.ReadLine();
}
static Func<int, int, double> IL_EmbedConst(int b)
{
var method = new DynamicMethod("EmbedConstIL", typeof(double), new[] { typeof(int), typeof(int) });
var log = typeof(Math).GetMethod("Log", new Type[] { typeof(double) });
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldc_I4, b);
il.Emit(OpCodes.Mul);
il.Emit(OpCodes.Conv_R8);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldc_I4, b);
il.Emit(OpCodes.Mul);
il.Emit(OpCodes.Conv_R8);
il.Emit(OpCodes.Call, log);
il.Emit(OpCodes.Sub);
il.Emit(OpCodes.Ret);
return (Func<int, int, double>)method.CreateDelegate(typeof(Func<int, int, double>));
}
static Func<int, int, double> EmbedConstFunc(int b)
{
return (a, z) => a * b - Math.Log(z * b);
}
}