我有一个简单的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
{
}
}
答案 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;
}