我写了段代码,大意是一个函数CCC需要传入一个委托action并在其内部执行,在AAA我是直接写了个匿名函数,在BBB则是传入一个符合委托规范的DDD函数,大概是这样的
static int len = 1024 * 1024;
static void AAA() {
Stopwatch sw = new Stopwatch();
sw.Start();
int a = 0;
for (int i = 0; i < len; i++) {
a += CCC(() => {
return 1;
});
}
Console.WriteLine(sw.ElapsedTicks);
}
static void BBB() {
Stopwatch sw = new Stopwatch();
sw.Start();
int a = 0;
for (int i = 0; i < len; i++) {
a += CCC(DDD);
}
Console.WriteLine(sw.ElapsedTicks);
}
static int CCC(Func<int> action) {
return action();
}
static int DDD() {
return 1;
}
然后经过多次测试,发现AAA的执行速度明显比BBB快,平均AAA比BBB快了一倍左右,这我就很奇怪了,BBB传入的是现成的DDD函数,执行的时候只是来回折腾一个已有的引用,而AAA每次都要临时创建一个匿名函数,明显应该比BBB处理的事情更多啊,但是测试结果AAA就是比BBB快,有没有大佬帮忙看下是我哪里理解错了啊,指点下小弟
太晚了,懒得测试,只说一点,你传ddd进去依然要创建委托实例的,他不是现成的函数。至于效率我没有研究过,不清楚
大佬能详细的讲讲吗,我不是很明白啊
@WmW: 把这段代码复制到LinqPad中,用C#Program模式,按F5运行,切换到结果的IL标签页,就可以看到IL代码,我把核心的部分复制过来了,简单讲一下
AAA:
...
IL_0013: ldsfld UserQuery+<>c.<>9__6_0 // 读取静态字段,这个静态字段是用来保存Func<int>委托的
IL_0018: dup
IL_0019: brtrue.s IL_0032 //如果这个变量不为空,跳转到0032行,即调用CCC方法那行,否则继续执行
IL_001B: pop
IL_001C: ldsfld UserQuery+<>c.<>9
IL_0021: ldftn UserQuery+<>c.<AAA>b__6_0
IL_0027: newobj System.Func<System.Int32>..ctor // 初始化Func<int>委托
IL_002C: dup
IL_002D: stsfld UserQuery+<>c.<>9__6_0 // 把创建好的委托保存到静态字段
IL_0032: call UserQuery.CCC // 调用CCC
...
BBB:
...
IL_0014: ldftn UserQuery.DDD // 获取DDD的指针
IL_001A: newobj System.Func<System.Int32>..ctor // 创建Func<int>委托
IL_001F: call UserQuery.CCC // 调用CCC
...
可以看到,lambda表达式创建委托之后,被保存到一个静态字段里面了,下次判断非空直接使用了,而BBB方法中,还是每次创建一次Func<int>委托,这个自然就慢了。
如果把BBB方法改成这样:
static void BBB()
{
Stopwatch sw = new Stopwatch();
sw.Start();
int a = 0;
Func<int> ddd = DDD;
for (int i = 0; i < len; i++)
{
a += CCC(ddd);
}
Console.WriteLine(sw.ElapsedTicks);
}
调用速度就会变得差不多,其实就是一个有缓存,一个没有,导致速度差别巨大。
@拓拓: 万分感谢~