【问题标题】:What's wrong with Loop speed?循环速度有什么问题?
【发布时间】:2014-01-25 10:05:49
【问题描述】:

我有这个简单的for 循环,里面什么都没有。现在运行几乎需要 2 秒,但如果我将 _img.width 替换为 512,那么它几乎可以在 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
    {
    }
}

【问题讨论】:

  • _img.Width本身的值原来也是512?也许这是一个必须首先计算的属性并且会占用时间?
  • 正如 DrCopyPaste 建议的那样,将 _img.Width 和 _img.Height 移出循环到局部变量中,以检查值是否需要时间加载。过去我在访问远程打印机设置时就是这种情况。

标签: c# performance loops for-loop


【解决方案1】:

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

它不仅仅是一个数字,它是一个属性。不幸的是,对于一个不平凡的实现,涉及到的底层非托管互操作调用并不便宜。由于 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)
    {
    }
}

【讨论】:

  • 谢谢,这是我为提高速度所做的。它显着减少了整个循环的时间。
【解决方案2】:

查看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

【讨论】:

    【解决方案3】:

    正如 cmets 中所建议的,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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多