GDI+Image比C#Image快得多

GDI+ Image EXTREMELY faster than C# Image

本文关键字:快得多 C#Image GDI+Image      更新时间:2023-10-16

我决定在C#和C++中对阅读图像进行基准测试,以决定在我正在考虑为自己制作的项目中使用哪种语言
我预计基准测试会非常接近,C++可能会稍微领先一点。

C#代码每次运行大约需要300ms(我每次测试运行100次),其中C++代码大约需要1.5ms

那么我的C#代码错了吗?我的基准测试不好吗?还是真的慢了这么多?

这是我使用的c#代码:

Stopwatch watch = new Stopwatch();
watch.Start();
Image image = Image.FromFile(imagePath);
watch.Stop();
Console.WriteLine("DEBUG: {0}", watch.ElapsedMilliseconds);

C++代码几乎可以归结为:

QueryPerformanceCounter(&start);
Image * img = Image::FromFile(imagePath);
QueryPerformanceCounter(&stop);
delete img;
return (stop.QuadPart - start.QuadPart) * 1000.0 / freq.QuadPart;

不管是哪种语言,它们都需要最终出现在Image对象中,因为它提供了我需要的功能。

====================================================

正如xanatos在评论中指出的那样,Image.FromFile确实进行了检查。

更具体地说,这个:

num = SafeNativeMethods.Gdip.GdipImageForceValidation(new HandleRef(null, zero));
if (num != 0)
{
    SafeNativeMethods.Gdip.GdipDisposeImage(new HandleRef(null, zero));
    throw SafeNativeMethods.Gdip.StatusException(num);
}

使用Image.FromStream()可以避免这种情况。

我想知道的是,如果你确实避免了这种情况,并试图加载一个无效的图像文件,它会引发OutOfMemory异常
在C++中,你不会这样做检查。那么,这种检查有多重要呢?有人能给我一个避免这种情况会很糟糕的情况吗?

是的,您的基准测试存在缺陷。问题是,您忘记了实际对位图执行操作。就像油漆一样。

GDI+极大地优化了图像的加载。与.NET优化加载程序集的方式非常相似。它只做一些必要的事情,读取文件的头以检索基本属性。格式、宽度、高度、Dpi。然后,它创建一个内存映射文件,以创建到文件中像素数据的映射。但实际上并没有读取像素数据。

现在,差异开始发挥作用。System.Drawing.Image接下来实际读取像素数据。这会导致页面错误,操作系统现在读取文件并将像素数据复制到RAM中。非常理想的是,如果文件有任何问题,那么您将在FromFile()调用中得到一个异常,而不是稍后,通常是当您的程序绘制图像并隐藏在您没有编写的框架代码中时。C#代码的基准点乘以mmf的创建加上像素数据的读取。

C++程序总是要为读取像素数据付费。但你没有衡量这一点,你只衡量了创建MMF的成本。

我知道的几个要点

有一种东西叫做CLR。如果上述c++框架(似乎是Qt)使用了不依赖于.net框架的系统调用,那么它显然会运行得很快。

关于c#=>可以在代码中调用该程序集之前加载该程序集。如果你这样做,那么你可以发现它的牢度很好。

如果你使用windows平台,那么除非有必要,否则MS不会降低自己语言的执行速度。