我们在C#while循环中遇到了性能问题。循环非常缓慢只做一个简单的数学计算。事实证明parmIn
可以是从999999999到MaxInt的任何数字。我们没有预料到parmIn
的巨大价值。我们使用不同的方法修复了代码。
为了简单起见,编码循环进行了一次数学计算。我只是想知道包含一个简单数学计算的while循环的单次迭代的实际执行时间是什么?
int v1=0;
while(v1 < parmIn) {
v1+=parmIn2;
}
答案 0 :(得分:9)
此处还有其他事情发生。以下内容将在约100毫秒内完成。你说parmIn可以接近MaxInt。如果这是真的,那么ParmIn2是> 1,你没有检查你的int + new int是否会溢出。如果ParmIn >= MaxInt - parmIn2
,您的循环可能永远不会完成,因为它将回滚到MinInt并继续。
static void Main(string[] args)
{
int i = 0;
int x = int.MaxValue - 50;
int z = 42;
System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
st.Start();
while (i < x)
{
i += z;
}
st.Stop();
Console.WriteLine(st.Elapsed.Milliseconds.ToString());
Console.ReadLine();
}
答案 1 :(得分:2)
假设一个最佳编译器,它应该是一个检查while条件的操作,以及一个执行添加的操作。
答案 2 :(得分:1)
时间很小,只执行你问题中显示的循环的一次迭代就是......惊讶......小。
但是,它取决于实际的CPU速度,以及 的确如此
。它应该只是一些机器指令,因此在迭代过程中传递一次的循环次数不多,但可能需要几个循环才能循环备份,尤其是在分支预测失败的情况下。
在任何情况下,显示的代码都会受到:
parmIn
很大,你可以通过计算你必须执行的循环迭代次数来获得更快的代码,并进行乘法运算。 (再次注意,这可能是一个不正确的假设,这就是为什么只有一种确定的方法可以找到性能问题,衡量度量衡量)你的真正的问题是什么?
答案 3 :(得分:0)
这取决于您使用的处理器及其执行的计算。 (例如,即使在一些现代架构中,加法可能只需要一个时钟周期,但除法可能需要很多时钟周期。有一个比较来确定循环是否应该继续,这可能是一个时钟周期,然后分支回到循环的开始,这可能需要任意数量的循环,具体取决于管道大小和分支预测)
恕我直言,了解更多内容的最佳方法是将您感兴趣的代码放入一个非常大的循环(数百万次迭代),循环时间,并除以迭代次数 - 这将让您了解如何这需要每次迭代循环。 (在你的电脑上)。您可以尝试不同的操作,并了解一下您的PC如何工作。我更喜欢这种“亲自动手”的方式(至少从一开始),因为你可以从物理上尝试学到更多,而不仅仅是让别人告诉你答案。
答案 4 :(得分:0)
while循环是几条指令和一条数学运算指令。你真的在寻找一次迭代的最短执行时间。这是你所做的大量迭代,这会让你失望。
请注意,像这样的紧密循环也会对其他事情产生影响,因为它会使一个CPU陷入困境并阻塞UI线程(如果它在其上运行)。因此,由于操作次数不仅很慢,而且由于整个机器看起来没有反应而增加了感知性的冲击力。
答案 5 :(得分:0)
如果您对实际执行时间感兴趣,为什么不为自己计时并找出答案?
int parmIn = 10 * 1000 * 1000; // 10 million
int v1=0;
Stopwatch sw = Stopwatch.StartNew();
while(v1 < parmIn) {
v1+=parmIn2;
}
sw.Stop();
double opsPerSec = (double)parmIn / sw.Elapsed.TotalSeconds;
当然,一次迭代的时间是1/opsPerSec
。
答案 6 :(得分:0)
每当有人询问你知道他们试图优化错误的任何语言的控制结构有多快。如果您发现自己正在将所有i++
更改为++i
或将所有switch
更改为if...else
以获得速度,那么您将进行微观优化。微优化几乎从未给你你想要的速度。相反,想一想你真正想要做的事情,并设计一个更好的方法去做。
我不确定你发布的代码是否真的是你打算做的,或者它是否只是简单的循环被剥离到你认为导致问题的那个。如果它是前者那么你要做的是找到一个小于另一个数字的数字的最大值。如果这真的是你想要的那么你真的不需要循环:
// assuming v1, parmIn and parmIn2 are integers,
// and you want the largest number (v1) that is
// smaller than parmIn but is a multiple of parmIn2.
// AGAIN, assuming INTEGER MATH:
v1 = (parmIn/parmIn2)*parmIn2;
编辑:我刚刚意识到最初编写的代码给出的最小数字是parmIn2的倍数,大于parmIn。所以正确的代码是:
v1 = ((parmIn/parmIn2)*parmIn2)+parmIn2;
如果这不是你真正想要的,那么我的建议仍然是相同的:想一想你真正想做什么(或在Stackoverflow上询问)而不是试图找出天气while
或{{ 1}}更快。当然,您不会总是找到问题的数学解决方案。在这种情况下,还有其他策略可以降低所采用的循环次数。这是基于你当前问题的一个:继续加倍增量器,直到它太大,然后退回直到它恰到好处:
for
这是另一种加速循环的替代方案:
int v1=0;
int incrementer=parmIn2;
// keep doubling the incrementer to
// speed up the loop:
while(v1 < parmIn) {
v1+=incrementer;
incrementer=incrementer*2;
}
// now v1 is too big, back off
// and resume normal loop:
v1-=incrementer;
while(v1 < parmIn) {
v1+=parmIn2;
}
根据我的经验,特别是对于要处理数百万像素或多边形的图形编程,加速代码通常需要添加更多代码,这会转换为更多的处理器指令,而不是试图找到最少的指令可用于手头的任务。诀窍是避免处理你不需要的东西。