gpt4 book ai didi

c# - 并行调整图像大小导致内存不足异常

转载 作者:行者123 更新时间:2023-11-30 21:41:38 25 4
gpt4 key购买 nike

我正在将大量图像并行调整为 1000x1000 缩略图,但很快就耗尽了内存。 (性能分析器让我在大约 3 分钟后使用了 3GB 的内存)

最初我使用的是 Image.FromFile()但做了一些研究,我发现 Image.FromStream()是要走的路。我认为我有适当的 using 语句,某处仍然在内存中保留内容并且 GC 没有按预期清除资源。

似乎 GDI+ 保持句柄打开有问题,但我似乎找不到适合我的情况的解决方案。

问题:

  1. 我做错了什么吗?
  2. 如果没有,有没有更好的方法Dispose()流/图像/ResizedImage,这样我就不会耗尽所有资源,同时仍然保持快速的并行操作?
  3. 如果 GDI+ 是问题所在并且使非托管资源保持事件状态,我该如何解决该问题?

代码

List<FileInfo> files包含 ~300 张有效的 JPG 图片,每张 JPG ~2-4mb

来电者

    public void Execute()
{
Parallel.ForEach(Files, (file) =>
{
Resize.ResizeImage(file.FullName);
}
);
}

Execute()调用 Parallel.Foreach()..

调整类大小

public static class Resize
{
public static void ResizeImage(string fileName)
{
ResizeImage(fileName, 1000, 1000, true);
}

public static void ResizeImage(string fileName, int newHeight, int newWidth, bool keepAspectRatio = true)
{
string saveto = Path.GetDirectoryName(fileName) + @"\Alternate\" + Path.GetFileName(fileName);
try
{
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
using (Image ImageFromStream = Image.FromStream(fs))
{
var ImageSize = new Size(newHeight, newWidth);
if (keepAspectRatio)
{
int oWidth = ImageFromStream.Width;
int oHeight = ImageFromStream.Height;
double pWidth = ((double)ImageSize.Width / (double)oWidth);
double pHeight = ((double)ImageSize.Height / (double)oWidth);
double percent;
if (pHeight < pWidth)
percent = pHeight;
else
percent = pWidth;
newWidth = (int)(oWidth * percent);
newHeight = (int)(oHeight * percent);
}
else
{
newWidth = ImageSize.Width;
newHeight = ImageSize.Height;
}
var ResizedImage = new Bitmap(newWidth, newHeight);
using (Graphics gfxHandle = Graphics.FromImage(ResizedImage))
{
gfxHandle.InterpolationMode = InterpolationMode.HighQualityBicubic;
gfxHandle.DrawImage(ImageFromStream, 0, 0, newWidth, newHeight);
if (!Directory.Exists(Path.GetDirectoryName(saveto))) { Directory.CreateDirectory(Path.GetDirectoryName(saveto)); }
ResizedImage.Save(saveto, ImageFormat.Jpeg);
}
ResizedImage.Dispose();
ResizedImage = null;
}
}
}
catch (Exception ex)
{
Debug.WriteLine(string.Format("Exception: {0}", ex.Message));
}
}

最佳答案

This explanation并行性指出我的 Parallel.ForEach() 基本上是在创建过多的新任务,因为它正在等待磁盘访问。在大约 5 分钟标记处,大约在抛出异常时,大约有 160 个线程。降低并行度会限制创建的线程数量,以及内存中等待完成加载或写入磁盘之前超出范围并被处理的图像数量。设置 MaxDegreeOfParallelism = 2 似乎是网络磁盘访问的最佳点,并将我的线程数减少到 25 左右,并将 CPU 利用率提高到大约 35%(由于 GC 阻塞,从 17-24% 上升)线程,以及太多线程导致的 CPU 开销)

    public void Execute()
{
//Parallel.ForEach(Files, (file) =>
//{
// Resize.ResizeImage(file.FullName);
//}
//);

Parallel.ForEach(Files, new ParallelOptions() { MaxDegreeOfParallelism = 2 }, (file) => { Resize.ResizeImage(file.FullName); } );

}

谢谢@ZacFaragher。

关于c# - 并行调整图像大小导致内存不足异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43107228/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com