在循环内部使用IF语句与循环外部

时间:2016-08-03 10:55:36

标签: c# .net

我有一个带有嵌套嵌套嵌套循环的程序(共有四个循环)。我有一个布尔变量,我想在最深的循环和第一个嵌套循环中影响少量的代码。我的困境是,我真的不想把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();
        }
    }
}

就代码的作用而言,它是一个使用圆形内核的盒子模糊。

3 个答案:

答案 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();
}