C# · 12月 30, 2021

c# – 在for循环内声明的变量是否会影响循环的性能?

我已经做了我的功课,发现重复的保证,它表现没有什么不同,无论你在你的for循环内部或外部声明你的变量,它实际上编译成同样的MSIL.但是我一直在努力,但是发现在循环中移动变量声明确实会导致相当大的一致的性能增益.

我已经写了一个小的控制台测试类来衡量这个效果.我初始化一个static double []数组项,两个方法对它执行循环操作,将结果写入静态double []数组缓冲区.最初,我的方法是我注意到差异的方法,即复数的幅度计算.对于长度为1000000的项目数组运行这些数组100次,对于循环中变量(6个双变量)的运行时间一直较低,例如:32,83±0,64 ms v 43,44使用Intel Core 2 Duo @ 2.66 GHz的老年人配置为±0,45 ms.我尝试以不同的顺序执行它们,但并不影响结果.

然后我意识到,计算一个复数的大小远远不是一个最小的工作实例,并且测试了两个更简单的方法:

static void Square1() { double x; for (int i = 0; i < buffer.Length; i++) { x = items[i]; buffer[i] = x * x; } } static void Square2() { for (int i = 0; i < buffer.Length; i++) { double x; x = items[i]; buffer[i] = x * x; } }

有了这些,结果出来了另一种方式:声明环外的变量似乎更有利:对于Square2(),Square1()v为7.07±0.43 ms为12.07±0.51 ms.

我不熟悉ILDASM,但是我已经拆卸了两种方法,唯一的区别似乎是局部变量的初始化:

.locals init ([0] float64 x,[1] int32 i,[2] bool CS$4$0000)

在Square1()v

.locals init ([0] int32 i,[1] float64 x,[2] bool CS$4$0000)

在Square2()中.根据它,stloc.1在一个是stloc.0在另一个,反之亦然.在较长的复数量级计算中,MSIL代码甚至代码大小不同,我在内部声明代码中存在stloc.0的外部声明代码中看到了stloc.s i.

那怎么可能呢?我是忽略某些东西还是真正的效果?如果是这样,它可以在长循环的性能上有显着差异,所以我认为它值得一些讨论.

你的想法非常感激.

编辑:我忽略的一件事是在发布之前在几台电脑上进行测试.我现在在i5上运行它,两种方法的结果几乎相同.对于发表了这样的误导性观察,我深表歉意.

解决方法 任何有价值的C#编译器都会为您执行这样的微型优化.如果需要,只能在范围外泄漏一个变量.

所以保持double x;内部循环,如果可能的话.

不过,如果项目[i]是普通数据数组访问,那么我会写缓冲区[i] =项目[i] *项目[i]. C和C会优化,但我不认为C#是(还);你的拆卸意味着它没有.