我正在一个网站上工作,我需要能够将 4000x6000 左右的图像拆分为 4 个部分(在许多其他任务中),并且我需要这对多个用户来说尽可能快。
我目前的代码是
var bitmaps = new RenderTargetBitmap[elements.Length];
using (var stream = blobService.Stream(key))
{
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.StreamSource = stream;
bi.EndInit();
for (var i = 0; i < elements.Length; i++)
{
var element = elements[i];
TransformGroup transformGroup = new TransformGroup();
TranslateTransform translateTransform = new TranslateTransform();
translateTransform.X = -element.Left;
translateTransform.Y = -element.Top;
transformGroup.Children.Add(translateTransform);
DrawingVisual vis = new DrawingVisual();
DrawingContext cont = vis.RenderOpen();
cont.PushTransform(transformGroup);
cont.DrawImage(bi, new Rect(new Size(bi.PixelWidth, bi.PixelHeight)));
cont.Close();
RenderTargetBitmap rtb = new RenderTargetBitmap(element.Width, element.Height, 96d, 96d, PixelFormats.Default);
rtb.Render(vis);
bitmaps[i] = rtb;
}
}
for (var i = 0; i < bitmaps.Length; i++)
{
using (MemoryStream ms = new MemoryStream())
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmaps[i]));
encoder.Save(ms);
var regionKey = WebPath.Variant(key, elements[i].Id);
saveBlobService.Save("image/png", regionKey, ms);
}
}
我正在运行多个线程,这些线程将作业从队列中取出。我发现如果这部分代码一次被 4 个线程命中,我会得到 OutOfMemory 异常。我可以通过将上面的所有代码包装在 a 中来阻止这种情况发生,lock(obj)
但这并不理想。我尝试只包装第一个 using 块(从磁盘读取文件并拆分),但我仍然遇到内存不足异常(这部分代码执行得非常快)。
- 考虑到这应该占用的内存量,这很正常吗?
- 我可以做任何优化吗?
- 我可以增加可用内存吗?
更新:
根据 Moozhe 的帮助,我的新代码
public static void GenerateRegions(this IBlobService blobService, string key, Element[] elements)
{
using (var stream = blobService.Stream(key))
{
foreach (var element in elements)
{
stream.Position = 0;
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.SourceRect = new Int32Rect(element.Left, element.Top, element.Width, element.Height);
bi.StreamSource = stream;
bi.EndInit();
DrawingVisual vis = new DrawingVisual();
DrawingContext cont = vis.RenderOpen();
cont.DrawImage(bi, new Rect(new Size(element.Width, element.Height)));
cont.Close();
RenderTargetBitmap rtb = new RenderTargetBitmap(element.Width, element.Height, 96d, 96d, PixelFormats.Default);
rtb.Render(vis);
using (MemoryStream ms = new MemoryStream())
{
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtb));
encoder.Save(ms);
var regionKey = WebPath.Variant(key, element.Id);
blobService.Save("image/png", regionKey, ms);
}
}
}
}