【发布时间】:2014-07-22 08:06:18
【问题描述】:
我是 C# 和并行处理的新手。我正在尝试处理一堆图像,我已经编写了处理方法。我在 imagelist 上添加了并行 foreach 循环,如下所示
Parallel.ForEach(Directory.GetFiles(path), new ParallelOptions { MaxDegreeOfParallelism = 2 }, fileName =>
{
List<string> tempList = new List<string>();
using (Bitmap imageBitmap= new Bitmap(fileName))
{
using (ImageProcessor imageProcessor= new ImageProcessor ())
{
tempList = imageProcessor.ProcessImage(imageBitmap);
}
}
if (tempList.Count != 0)
allElements.Add(tempList.FirstOrDefault());
});
在其中一种方法中,我使用LockBits 方法获取图像的BitMapData 并将该数据复制到byte[] 但方法抛出异常,方法代码是
private byte[] ImageToByteArray(Bitmap b, out int stride)
{
object sync = new object();
BitmapData bd;
lock (sync)
{
Rectangle rect = new Rectangle(0, 0, b.Width, b.Height);
bd = b.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);//This line throwing the exception.
try
{
byte[] pxl = new byte[bd.Stride * b.Height];
Marshal.Copy(bd.Scan0, pxl, 0, bd.Stride * b.Height);
stride = bd.Stride;
return pxl;
}
finally
{
b.UnlockBits(bd);
}
}
}
我尝试lock 使用LockBits 方法的代码,因此一次只有一个线程使用代码,因此使用内存。
我还尝试使用lock 调用父方法中的方法,例如
public List<string> ProcessImage(BitMap image)
{
object sync = new object();
int stride;
byte[] rawImg;
using (image)
{
lock (sync)
{
rawImg = ImageToByteArray(image, out stride);
}
processingImg = new ProcessImage(rawImg, image.Width, image.Height);
}
}
但仍然存在例外。异常没有给我任何堆栈跟踪或解释,我收到的异常消息是Out Of Memory。
我遇到了this 答案,当我减少MaximumDegreeOfParallelism 时,它工作正常。
所以基本上我想知道,
1)为什么即使代码上有lock,代码也会为超过2个线程抛出Out Of Memory异常?
2)如果我增加DegreeOfParallelism,是否可以避免这个异常?
任何帮助都会很棒。
如有任何疑问,请随时发表评论。
【问题讨论】:
-
ProcessImage中的lock没有用,因为您锁定了本地对象。并且使用using (variable)通常是非常有问题的,因为您可以处置不属于您的对象。 -
Bitmap.LockBits 将分配一大块内存。 Parallel.ForEach 将继续典当和执行任务,直到 2 个 CPU 内核被完全占用。每个任务将在内存中加载图像并锁定其位。因此,可以假设您在 2 个处理器内核被完全占用之前内存不足。尝试在 BlockingCollection 中生成一个加载图像的任务,该任务具有有限的 X 和 2 个处理这些预取图像的消费者的容量。
标签: c# c#-4.0 image-processing parallel-processing lockbits