在并行缩放多个Bitmap时,我无法获得任何速度增益。
请查看以下代码以说明问题:
class Program
{
static void Main(string[] args)
{
Bitmap[] images = Enumerable.Range(0, 8).Select(_ => new Bitmap(6000, 4000, PixelFormat.Format24bppRgb)).ToArray();
Bitmap[] scaledImages = Enumerable.Range(0, 8).Select(_ => new Bitmap(600, 400, PixelFormat.Format24bppRgb)).ToArray();
// Sequential image scaling:
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for(int i = 0; i < images.Length; i++)
{
ImageScaler(images[i], scaledImages[i]);
}
stopwatch.Stop();
Console.WriteLine($"Sequential scaling: {images.Length} images in {stopwatch.ElapsedMilliseconds} ms.");
// Parallel image scaling:
stopwatch.Restart();
Parallel.For(0, images.Length, i => ImageScaler(images[i], scaledImages[i]));
stopwatch.Stop();
Console.WriteLine($"Parallel scaling: {images.Length} images in {stopwatch.ElapsedMilliseconds} ms.");
Console.ReadKey();
}
private static void ImageScaler(Bitmap source, Bitmap destination)
{
using(Graphics g = Graphics.FromImage(destination))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(source, 0, 0, destination.Width, destination.Height);
}
}
}
我的系统(最近的四核i7)得到以下结果:
Sequential scaling: 8 images in 1774 ms.
Parallel scaling: 8 images in 1792 ms.
这是一个意外的结果有两个原因:
为验证这一点,我通过以下基本图像缩放算法替换了上面代码中的ImageScaler()
:
private static unsafe void NaiveImageScaler(Bitmap src, Bitmap dst)
{
BitmapData srcBd = src.LockBits(new Rectangle(0, 0, src.Width, src.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
BitmapData dstBd = dst.LockBits(new Rectangle(0, 0, dst.Width, dst.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
unsafe
{
byte* srcBgr = (byte*)srcBd.Scan0.ToPointer();
byte* dstBgr = (byte*)dstBd.Scan0.ToPointer();
for(int yd=0; yd<dst.Height; yd++)
{
for(int xd = 0; xd < dst.Width; xd++)
{
int bSum = 0, gSum = 0, rSum = 0;
for(int ys = 10*yd; ys < 10*yd+10; ys++)
{
for(int xs = 10*xd; xs < 10*xd+10; xs++)
{
bSum += srcBgr[ys * srcBd.Stride + 3 * xs];
gSum += srcBgr[ys * srcBd.Stride + 3 * xs + 1];
rSum += srcBgr[ys * srcBd.Stride + 3 * xs + 2];
}
}
dstBgr[yd * dstBd.Stride + 3 * xd] = (Byte)(bSum / 100);
dstBgr[yd * dstBd.Stride + 3 * xd + 1] = (Byte)(bSum / 100);
dstBgr[yd * dstBd.Stride + 3 * xd + 2] = (Byte)(bSum / 100);
}
}
}
dst.UnlockBits(dstBd);
src.UnlockBits(srcBd);
}
使用此代码,我得到以下结果:
Sequential scaling: 8 images in 660 ms.
Parallel scaling: 8 images in 184 ms.
并行实现现在比顺序实现快3.6倍。
为什么两种方法之间的差异基本上完成了相同的工作? System.Drawing中是否存在阻止运行并行代码的限制?
关于&#34;标记为重复的评论&#34;:
我不认为Multithreading System.Windows.Graphics完全相同。提到的问题是关于绘图,这个是关于图像缩放。受试者是相关的,但并不完全相同。
我同意基本解释(GDI中的关键区域)适用于这两个问题。
我相信我发现了更接近我自己的问题(!): Parallelizing GDI+ Image Resizing .net