首页 新闻 会员 周边 捐助

C# 这段代码的使用匿名函数为什么比使用已经定义的函数速度快啊

0
悬赏园豆:10 [已解决问题] 解决于 2021-06-11 10:05

我写了段代码,大意是一个函数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快,有没有大佬帮忙看下是我哪里理解错了啊,指点下小弟

C#
WmW的主页 WmW | 菜鸟二级 | 园豆:424
提问于:2021-06-09 17:07
< >
分享
最佳答案
0

太晚了,懒得测试,只说一点,你传ddd进去依然要创建委托实例的,他不是现成的函数。至于效率我没有研究过,不清楚

收获园豆:10
拓拓 | 小虾三级 |园豆:1055 | 2021-06-09 23:19

大佬能详细的讲讲吗,我不是很明白啊

WmW | 园豆:424 (菜鸟二级) | 2021-06-10 16:36

@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);
}

调用速度就会变得差不多,其实就是一个有缓存,一个没有,导致速度差别巨大。

拓拓 | 园豆:1055 (小虾三级) | 2021-06-10 22:02

@拓拓: 万分感谢~

WmW | 园豆:424 (菜鸟二级) | 2021-06-11 10:04
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册