【问题标题】:Property call in for-loop design issuefor循环设计问题中的属性调用
【发布时间】:2014-01-23 08:15:10
【问题描述】:

我今天早上与同事讨论了 for-loop-optimization。这与this question 中描述的情况差不多,但是代码是 C++/CLI,并且方法来自不同的程序集。我知道在这种情况下,编译器无法通过内联函数来优化循环。但是,主题是图像处理,调用的属性是图像的宽度和高度,即:

for (unsigned int y = 0; y < image.Height; ++y) {
    for (unsigned int x = 0; x < image.Width; ++x) {
        // Do something with pixel x,y
    }
}

对于 5M 灰度图像,该循环大约需要 450 毫秒,而在执行循环之前将宽度和高度保存到局部变量时,耗时大约 10 毫秒! (这些数字仅用于显示差异的大小。)

当然,我们现在正走向局部变量解决方案,但我想知道上面给出的幼稚 for 循环是否真的是糟糕的设计?在编写这样的代码时,我不希望有任何真正的编译器优化,但调用 trivial 属性,如图像的宽度和高度,我希望能更快地返回它们的值。那么,整个问题难道不是由于图像库作者的糟糕设计造成的吗?使用琐碎的属性时,我不应该牺牲可读性吗?

【问题讨论】:

  • 您是否在没有附加调试器和发布版本的情况下对此进行了测量?
  • “我不应该保留可读性吗?” - 好吧,我不相信首先将两个属性保存到局部变量会降低可读性,但我想知道你的编译器设置和环境。
  • ...when the runtime is run in debugging mode, the JIT compiler will not perform certain optimizations,所以如果你在调试模式下测量,不要假设内联会发生。
  • 当然是在发布模式下运行的。
  • 是的,两个本地人不会影响可读性,但我想知道这些属性是否应该设计在循环中使用。

标签: .net for-loop properties c++-cli


【解决方案1】:

我同意设计决策有点奇怪,至少表面上如此。 System.Drawing 中的许多底层数据类型都映射到本机 GDI(?) 类型,这会使简单的事情变慢。

但很可能,一旦您真正想将图像绘制到屏幕上,它会加快速度,因为在实际绘制图像时没有额外映射到本机类型。

例如Image.Height的要领;

public int Height {
    get { 
        int height;
        int status = SafeNativeMethods.Gdip.GdipGetImageHeight(new HandleRef(this, nativeImage), out height); 

        if (status != SafeNativeMethods.Gdip.Ok) 
            throw SafeNativeMethods.Gdip.StatusException(status);

        return height;
    } 
}

内联此方法不一定会提高性能,大部分时间很可能花在本机调用获取实际高度上,这就是为什么只获取一次Height 而不是循环获取(在本例中为设计)让事情变得更快。

【讨论】:

  • OP 从未说过 imageSystem.Drawing.Bitmap。不过,这并不是一个荒谬的假设。
  • @EdS。实际上那是Image.HeightBitmap 是一个错字。
  • 这是一个第三方库,不是来自System.Drawing。但是,即使在这种情况下,您是否不希望包装器缓存像 height 这样的值以便更快地执行属性查询?
  • @Matz 我同意 100% 在可以避免的属性中进行工作并不是循环目的的最佳性能决策,但是它可以简化其他更难解决的代码路径.不过很难讨论第三方代码,尤其是在不知道你在说什么代码的情况下:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-21
  • 2015-10-07
相关资源
最近更新 更多