Loop速度有什么问题?

时间:2014-01-07 16:12:43

标签: c# performance loops for-loop

我有一个简单的for循环,里面什么都没有。现在运行需要将近2秒,但如果我用512替换_img.width,那么它几乎在0.001毫秒内运行。有什么问题?我应该分配一个局部变量而不是使用_img.width吗?我想知道为什么它运行得更快,因为它只是一个数字。

for (int aRowIndex = 0; aRowIndex < _img.width; aRowIndex += subsample)// For por cada fila de cada imagen
{
    for (int aColumnIndex = 0; aColumnIndex < _img.height; aColumnIndex += subsample)//For por cada columna
    {
    }
}

3 个答案:

答案 0 :(得分:11)

  

为什么它运行得更快,因为它只是一个数字

它不仅仅是一个数字,而是一个属性。不幸的是,有一个非常重要的实现,涉及的基础非托管互操作调用不是很便宜。由于O(n ^ 2)循环复杂性,它会爆炸到可观察到的开销。

您可以通过自己缓存属性值来解决它:

int width = _img.Width;
int height = _img.Height;
for (int aRowIndex = 0; aRowIndex < width; aRowIndex += subsample)
{
    for (int aColumnIndex = 0; aColumnIndex < height; aColumnIndex += subsample)
    {
    }
}

答案 1 :(得分:3)

查看Image.Height的.NET源代码,您可以看到每个类型都获得属性值,它会调用gdiplus.dll的外部调用。它不会将值缓存在.NET内存中。

/// <summary>Gets the height, in pixels, of this <see cref="T:System.Drawing.Image" />.</summary>
/// <returns>The height, in pixels, of this <see cref="T:System.Drawing.Image" />.</returns>
public int Height
{
    [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
    get
    {
        int result;
        int num = SafeNativeMethods.Gdip.GdipGetImageHeight(new HandleRef(this, this.nativeImage), out result);
        if (num != 0)
        {
            throw SafeNativeMethods.Gdip.StatusException(num);
        }
        return result;
    }
}

顺便说一句,这实际上违反了微软自己的准则:http://msdn.microsoft.com/en-us/library/vstudio/ms229054(v=vs.100).aspx

答案 2 :(得分:1)

正如评论中所建议的那样,Bitmap中的Width(继承自Image)的实现似乎不只是返回一个值。

如果您将使用ILdsm来查看实现,您会发现有一个非常昂贵的互操作。 这是来自“Reflector”的代码(比IL更易读):

[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public int get_Width()
{
    int num;
    int status = SafeNativeMethods.Gdip.GdipGetImageWidth(new HandleRef(this, this.nativeImage), out num);
    if (status != 0)
    {
        throw SafeNativeMethods.Gdip.StatusException(status);
    }
    return num;
}