我正在用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();
}
}
}
}
...
答案 0 :(得分:5)
您的样本中的直接分配应该非常好:
BooleanAnswerArray[index][x][y] = SomeFunction(index,x,y);
旁注:尝试缓存数组访问可能是个好主意 - 应该能够缓存var row = BooleanAnswerArray[index][x]
,以避免在最里面的循环中进行额外的索引。
使用if / else:
更新问题首先 - 这是性能问题,因此必须衡量不同的选项,看看代码是否符合目标。 Stopwatch
类通常足以进行此类本地化性能比较,否则可能需要分析器。
思考
if
将产生完全相同的影响,无论它是否具有一个或两个分支,尤其是在存在任何其他非平凡代码(如非内联函数调用)的情况下。 答案 1 :(得分:2)
在第一个我使用If-Else语句,在第二个我省略了 否则,因为If案件非常罕见。
这只意味着你的第二个程序与第一个程序完全不同(除非你能证明永远不需要else
......)。所以这不是性能问题,你的第二个程序错误(假设你的第一个程序是正确的,而其他是必需的)。
没有输出正确结果的快速程序是件坏事。
在这种特殊情况下,一个好的编译器会将代码优化为像alzaimar的答案。不过,为了便于阅读,你应该这样写它。
在一般情况下,其他人可能(将)通过名为branch prediction failure
的内容包含性能损失。现代CPU将“猜测”程序流是通过if
还是else
并执行该分支。如果它后来发现它做错了猜测它必须回溯并通过正确的分支。
如果这确实成为一个问题,您应该确保使用if
和else
分支的顺序遵循一个简单的模式。
有关详细信息,请参阅this问题及其答案。
性能下降的第二个原因是不利用称为数据局部性或locality of reference的东西。这意味着您应该使用靠近的数据(例如myArray [100]和myArray [101])。
在您的特定情况下,请勿更改数组索引的顺序。
先写一个正确的程序。然后在受伤的地方进行优化。也就是说,探查器显示您的程序花费了太多时间。优化无关紧要的事情是没有用的。
答案 2 :(得分:1)
什么阻止您按如下方式简化代码:
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);
抱歉踢踢牙套。我不太喜欢他们; - )
答案 3 :(得分:0)
第一个应该稍快一点。但如果我是你,我会更关心可读代码而不是表现良好的代码(直到你开始做数百万次的事情)...只是我的2c
答案 4 :(得分:0)
您的方法1只进行一次3级索引计算而不是两次。
编译器是否可以优化它是不确定的。
但当然,一切都取决于SomeFunction
使用的相对时间。