Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/apache-kafka/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# for循环中声明的变量会影响循环的性能吗?_C#_For Loop_Variable Declaration - Fatal编程技术网

C# for循环中声明的变量会影响循环的性能吗?

C# for循环中声明的变量会影响循环的性能吗?,c#,for-loop,variable-declaration,C#,For Loop,Variable Declaration,我已经完成了我的家庭作业,并且反复得到保证,无论在for循环内部还是外部声明变量,都不会对性能造成影响,而且它实际上编译到了非常相同的MSIL。但我一直在摆弄它,并发现在循环中移动变量声明确实会带来可观且一致的性能提升 我编写了一个小的控制台测试类来测量这种效果。我初始化一个静态double[]数组项,两个方法对其执行循环操作,将结果写入一个静态double[]数组缓冲区。最初,我的方法是那些我注意到差异的方法,即复数的量级计算。对长度为1000000的项目数组运行100次,对于变量(6doub

我已经完成了我的家庭作业,并且反复得到保证,无论在for循环内部还是外部声明变量,都不会对性能造成影响,而且它实际上编译到了非常相同的MSIL。但我一直在摆弄它,并发现在循环中移动变量声明确实会带来可观且一致的性能提升

我编写了一个小的控制台测试类来测量这种效果。我初始化一个静态
double[]
数组项,两个方法对其执行循环操作,将结果写入一个静态
double[]
数组缓冲区。最初,我的方法是那些我注意到差异的方法,即复数的量级计算。对长度为1000000的项目数组运行100次,对于变量(6
double
variables)位于循环内部的项目数组,我得到的运行时间始终较低:例如,在使用Intel Core 2 Duo@2.66 GHz的旧配置上,32,83±0,64 ms v 43,24±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;
        }
    }
Square1()中

Square2()
中。根据它,一个中的
stloc.1
就是另一个中的
stloc.0
,反之亦然。在较长的复杂震级计算MSIL代码中,甚至代码大小也不同,我在外部声明代码中看到了
stloc.si
,其中内部声明代码中有
stloc.0

这怎么可能呢?我是忽略了什么还是真的影响了?如果是的话,它会对长循环的性能产生显著的影响,因此我认为它值得一些讨论

非常感谢你的想法

编辑:我忽略了一件事,那就是在发布之前在几台计算机上测试它。我现在已经在i5上运行了它,两种方法的结果几乎相同。我为发布这样一个误导性的观察结果而道歉

任何称职的C#编译器都会为您执行这样的微优化。仅在必要时将变量泄漏到范围之外

所以保持
双x循环内部


但就个人而言,如果
items[i]
是普通的旧数据数组访问,那么我会写
buffer[i]=items[i]*items[i]。C和C++会优化这一点,但我不认为C()是这样的;您的反汇编意味着它没有。分析垃圾收集器对这两个变体所做的工作会很有趣

我可以想象,在第一种情况下,循环运行时不会收集变量
x
,因为它是在外部范围内声明的

在第二种情况下,
x
上的所有句柄将在每次迭代中删除

也许您可以使用新的C#4.6
GC.TryStartNoGCRegion
GC.EndNoGCRegion
再次运行测试,以查看性能影响是否源于GC


很好的调查,你肯定会赢得一张选票。@尼科里夫:的确,这是一个写得很好的问题。(遗憾的是,虽然我认为答案很琐碎。)我不能等待@JonSkeet的回答,我无法用给定的代码复制这种行为。生成的IL肯定会改变局部变量的声明顺序,但我看不出有任何显著的性能差异。您能展示一下用于度量性能的代码吗?您在第一次运行代码时考虑过JIT编译吗?非常感谢!我过去一直坚持在方法开始时声明所有变量的强迫性习惯,但从现在起我将三思而后行。如果我关心性能的话,我想说的是测试这两种安排,因为优化似乎可以在两个方向上都起作用。模糊的答案是“多年的经验告诉你,范围松散的变量最终会在一个完全混乱的代码库中结束。”.您的答案似乎是说,将变量保留在循环内部和外部之间不应有性能差异,但这并不能真正解释OP所经历的测量差异。有趣的是,我将这完全归咎于弹性标尺的概念。C#编译器偶尔会删除局部变量。我不确定它在什么条件下能做到,但我以前见过它这么做。谢谢,这是个好主意。我想已经测试过了,但目前我无法访问.NET4.6。SharpDevelop似乎并不支持它。我将尝试升级我的工具并返回到问题上来。我怀疑这与GC有任何关系
double
是一种值类型,在这种情况下,将被堆栈分配。它不会产生任何垃圾来清理。Eric Lippert在
      .locals init ([0] float64 x,
       [1] int32 i,
       [2] bool CS$4$0000)
      .locals init ([0] int32 i,
       [1] float64 x,
       [2] bool CS$4$0000)