在循环中使用Else语句会导致性能下降吗?

本文关键字:性能 循环 语句 Else | 更新日期: 2023-09-27 18:14:47

我正在用c#写一个蒙特卡罗模拟程序,我正在努力确保我写的代码尽可能高效——我正在运行数十亿个循环,事情变得越来越慢。我有一个关于在循环内使用Else语句的问题。

我的问题是:这两种方法在性能上有什么不同吗?在第一个语句中,我使用If-Else语句,而在第二个语句中,我省略了Else语句,因为If情况非常罕见。

编辑:让我们假设我需要做的不仅仅是在条件满足时分配true/false,这样直接分配就不是唯一需要做的事情。if-Else方法的执行速度一样快吗?

       //METHOD 1
 ...       
            for (int index = 0; index < 6; index++)
            {
                for (int x = 0; x < 50; x++)
                {
                    for (int y = 0; y < 50; y++)
                    {

                        bool ThingWhichIsVeryRarelyTrue = SomeFunction(index,x,y);
                        if (ThingWhichIsVeryRarelyTrue)
                        {
                            BooleanAnswerArray[index][x][y] = true;
                            DoSomeOtherStuff();
                        }
                        else
                        {
                            BooleanAnswerArray[index][x][y] = false;
                        }
                    }
                }
            }
    ...
    //METHOD 2
    for (int index = 0; index < 6; index++)
            {
                for (int x = 0; x < 50; x++)
                {
                    for (int y = 0; y < 50; y++)
                    {
                        BooleanAnswerArray[index][x][y] = false;
                        bool ThingWhichIsVeryRarelyTrue = SomeFunction(index,x,y);
                        if (ThingWhichIsVeryRarelyTrue)
                        {
                            BooleanAnswerArray[index][x][y] = true;
                            DoSomeOtherStuff();
                        }
                    }
                }
            }
...

在循环中使用Else语句会导致性能下降吗?

在您的示例中,直接赋值应该是完美的:

 BooleanAnswerArray[index][x][y] = SomeFunction(index,x,y);

旁注:尝试缓存数组访问可能是一个好主意-应该能够缓存var row = BooleanAnswerArray[index][x],这样你就可以避免在最内层循环中额外的索引。

使用if/else更新问题:

首先,这是一个性能问题,所以必须衡量不同的选项,看看代码是否满足目标。Stopwatch类通常足以进行这种局部性能比较,否则可能需要profiler。

猜测

  • if将导致完全相同的影响,无论它是否有一个或两个分支,特别是在存在任何其他不重要的代码,如非内联函数调用。
  • 循环展开可能会产生更大的影响(也会使代码可读性降低)
  • 尽可能多的缓存可能会产生更大的影响

在第一个语句中我使用了If-Else语句,在第二个语句中我省略了Else,因为If情况非常少见。

这仅仅意味着您的第二个程序不会完全像第一个程序一样执行(除非您可以证明永远不需要else…)。所以这不是性能问题,你的第二个程序是错误的(假设你的第一个程序是正确的,并且需要else)。

不输出正确结果的快速程序是一件坏事。

在这种特殊情况下,一个好的编译器会将代码优化为类似alzaimar的答案。不过,为了便于阅读,您也应该这样写。

在一般情况下,else可能(将)包含通过称为branch prediction failure的东西进行的性能损失。现代CPU会"猜测"程序流是经过if还是else,然后执行该分支。如果它后来发现它做了错误的猜测,它必须返回并通过正确的分支。

如果这确实成为一个问题,您应该确保使用ifelse分支的顺序遵循一个简单的模式。

请参阅这个问题及其答案了解更多细节。

性能下降的第二个原因是没有利用数据局部性或引用局部性。这意味着你应该使用紧密相连的数据(例如myArray[100]和myArray[101])。

在特殊情况下,不要改变数组的索引顺序。

先写一个正确的程序。然后优化它的痛处。也就是说,分析器显示你的程序花费了太多的时间。优化不重要的东西是没有用的

是什么阻碍了您将代码简化如下:

for (int index = 0; index < 6; index++)
  for (int x = 0; x < 50; x++)
    for (int y = 0; y < 50; y++)
      BooleanAnswerArray[index][x][y] = SomeFunction(index,x,y);

很抱歉踢括号。我不太喜欢他们;-)

第一个应该稍微快一点。但如果我是你,我会更关心代码的可读性,而不是代码的良好性能(直到你开始做数百万次的事情)……只是我的2c

方法1只计算一次3级索引,而不是两次。编译器能否对其进行优化还不确定。但是,当然,一切都取决于SomeFunction使用的相对时间。