我有一个带有嵌套嵌套嵌套循环的程序(共有四个循环)。我有一个布尔变量,我想在最深的循环和第一个嵌套循环中影响少量的代码。我的困境是,我真的不想把if else语句放在循环中,因为我认为这会在每次迭代时检查布尔状态,使用额外的时间来检查语句,我知道循环开始时布尔的状态不会改变。这让我认为最好将if else语句放在循环之外,只是让我的循环代码略有改变,但是,这看起来也很麻烦,有很多重复的代码。
我认为可能有用的一件事,但是我没有多少使用经验,是一个委托,我可以简单地将一些代码放在一个方法中然后创建一个委托,这取决于我可以分配的betterColor的状态
。事先用不同的代码委托方法,但这看起来也很混乱。以下是我想避免的事情,因为我认为这可能会减慢我的算法:
for (short y = 0; y < effectImage.Height; y++)
{
int vCalc = (y <= radius) ? 0 : y - radius;
for (short x = 0; x < effectImage.Width; x++)
{
int red = 0, green = 0, blue = 0;
short kArea = 0;
for (int v = vCalc; v <= y + radius && v < effectImage.Height; v++)
{
int calc = calcs[(y - v) + radius];
for (int h = (x <= calc || calc < 0) ? 0 : x - calc; h <= x + calc && h < effectImage.Width; h++)
{
if (betterColor == true)
{
red += colorImage[h, v].R * colorImage[h, v].R;
green += colorImage[h, v].G * colorImage[h, v].G;
blue += colorImage[h, v].B * colorImage[h, v].G;
kArea++;
}
}
}
if (betterColor == true)
effectImage.SetPixel(x, y, Color.FromArgb(red / kArea, green / kArea, blue / kArea));
else
effectImage.SetPixel(x, y, Color.FromArgb(Convert.ToInt32(Math.Sqrt(red / kArea)), Convert.ToInt32(Math.Sqrt(green / kArea)), Convert.ToInt32(Math.Sqrt(blue / kArea))));
}
if (y % 4 == 0) // Updates the image on screen every 4 y pixels calculated.
{
image.Image = effectImage;
image.Update();
}
}
以下是我的代码现在的样子:
if (betterColor == true)
{
for (short y = 0; y < effectImage.Height; y++)
{
int vCalc = (y <= radius) ? 0 : y - radius;
for (short x = 0; x < effectImage.Width; x++)
{
int red = 0, green = 0, blue = 0;
short kArea = 0;
for (int v = vCalc; v <= y + radius && v < effectImage.Height; v++)
{
int calc = calcs[(y - v) + radius];
for (int h = (x <= calc || calc < 0) ? 0 : x - calc; h <= x + calc && h < effectImage.Width; h++)
{
red += colorImage[h, v].R * colorImage[h, v].R;
green += colorImage[h, v].G * colorImage[h, v].G;
blue += colorImage[h, v].B * colorImage[h, v].G;
kArea++;
}
}
effectImage.SetPixel(x, y, Color.FromArgb(Convert.ToInt32(Math.Sqrt(red / kArea)), Convert.ToInt32(Math.Sqrt(green / kArea)), Convert.ToInt32(Math.Sqrt(blue / kArea))));
}
if (y % 4 == 0) // Updates the image on screen every 4 y pixels calculated.
{
image.Image = effectImage;
image.Update();
}
}
}
else
{
for (short y = 0; y < effectImage.Height; y++)
{
int vCalc = (y <= radius) ? 0 : y - radius;
for (short x = 0; x < effectImage.Width; x++)
{
int red = 0, green = 0, blue = 0;
short kArea = 0;
for (int v = vCalc; v <= y + radius && v < effectImage.Height; v++)
{
int calc = calcs[(y - v) + radius];
for (int h = (x <= calc || calc < 0) ? 0 : x - calc; h <= x + calc && h < effectImage.Width; h++)
{
red += colorImage[h, v].R;
green += colorImage[h, v].G;
blue += colorImage[h, v].B;
kArea++;
}
}
effectImage.SetPixel(x, y, Color.FromArgb(red / kArea, green / kArea, blue / kArea));
}
if (y % 4 == 0) // Updates the image on screen every 4 y pixels calculated.
{
image.Image = effectImage;
image.Update();
}
}
}
就代码的作用而言,它是一个使用圆形内核的盒子模糊。
答案 0 :(得分:10)
将if
移出循环,并有效地复制整个循环代码并不值得。所以如果你有这样的代码:
for (i …)
{
if (something)
DoX(i);
else
DoY(i);
}
然后你不应该用它替换它:
if (something)
{
for (i …)
DoX(i);
}
else
{
for (i …)
DoY(i);
}
这样做只会使代码很多更难以阅读和维护。首先需要弄清楚这实际上是针对每种情况执行的相同代码(除了之外的一个微小区别),并且一旦你需要改变关于循环的任何内容,它就非常难以维护你需要确保正确编辑这两种情况。
虽然从理论上讲,执行单次检查与执行检查N
次相比显然更快,但实际上这很少有用。依赖于常量布尔值的if分支是超快的,所以如果你计算循环外的条件(在你的情况下betterColor
被设置在循环之外),那么性能差异将根本不明显。此外,branch prediction通常会确保在这些情况下没有任何区别。
所以不,不要像那样重写那些代码。保持它更容易理解的方式。
一般来说,无论如何都应该避免这种微观优化。您的算法很可能具有慢得多的部分,这些部分与整体性能相比,比这样的小结构更加相关。因此,专注于已经非常快的那些小事情将无法帮助您更快地执行总执行。您应该只优化代码中的实际性能瓶颈,其中分析器显示存在性能问题或优化代码将主动提高性能。并远离优化,使代码不易读取,除非你真正需要它(在大多数情况下你不会)。
答案 1 :(得分:0)
我看到它的方式,代码并不等效(在你的第一个例子中,如果betterColor为false,则在最里面的循环中没有任何反应)。
但这不是微观优化吗?
您可以通过使用Func&lt;&gt;创建函数来执行某些操作。作为最内层循环的参数。然后根据betterColor值传递正确的func。
即。 Blur(betterColor?FuncA:FuncB);
虽然我不认为它会比布尔检查更快......但这是我的感觉。
答案 2 :(得分:-1)
将条件检查移到外面。尽管创建新变量可能比重复条件检查慢。首先是个人资料。
for (DoInLoop = something ? DoX : DoY …)
{
DoInLoop();
}