【发布时间】:2021-02-27 20:00:13
【问题描述】:
我对以不同方式形成基于 OR 的逻辑的性能影响感到好奇,因此我进行了一个简单且可能有点不科学的测试。我在 if 语句设置为 true(以触发案例 1)和设置为 false(以触发案例 2)的情况下运行了 10 次以下代码。我使用this site 测试代码并依赖其报告的“绝对运行时间”。
我得到的结果是,案例 1 的平均运行时间为 0.354 秒,而案例 2 的平均运行时间为 0.442 秒。这些数字在各个方面都相当一致——在案例 1 中,它们在 0.04 范围内变化,在案例 2 中,它们在 0.09 范围内变化,根本没有重叠,所以乍一看似乎是一个明显的差异。
这两种情况对计数器产生相同的结果 - 在这种情况下为 38571428,但我尝试的其他 toCount 值也相同。我的理解是,如果先前的 if 或 else-if 语句评估为 true,则不会评估 else-if 语句,因此从逻辑的角度来看,我认为这两种情况是在做同样的事情。
我对为什么案例 1 的性能优于案例 2 没有很好的直觉。有人可以对此有所了解吗?我对一般意义上感兴趣,为了更好地理解构建 C# 逻辑的不同方式可能会如何影响性能,所以我希望这个例子也可能有一些基本原则可以理解,但即使只是解释这个案例看起来很有趣。
int counter = 0;
int toCount = 50000000;
//Case 1
if (false)
{
for (int iNum = 0; iNum < toCount; ++iNum)
{
if (iNum % 2 == 0 || iNum % 3 == 0 || iNum % 5 == 0 || iNum % 7 == 0)
{
++counter;
}
}
}
//Case 2
else
{
for (int iNum = 0; iNum < toCount; ++iNum)
{
if (iNum % 2 == 0)
{
++counter;
}
else if (iNum % 3 == 0)
{
++counter;
}
else if (iNum % 5 == 0)
{
++counter;
}
else if (iNum % 7 == 0)
{
++counter;
}
}
}
Console.WriteLine("Result: " + counter.ToString());
【问题讨论】:
-
你编译和运行的优化级别是什么?
-
请注意,一个真正聪明的编译器会展开 2*3*5*7 次迭代的块,发现总是导致相同数量的匹配,并且实际上只需要遍历最终的部分块。
-
两个版本编译成different IL code:ifs明显更长,因此它的JITted汇编也更长。执行指令的数量不应该真的不同,但它足以不内联第二个版本(您可以尝试将
[MethodImpl(MethodImplOptions.AggressiveInlining)]应用于您的方法并再次检查差异)。而且也许 CPU 还可以更好地优化第一个版本的 JITted 代码的管道。
标签: c# performance if-statement syntax operators