C#保存位图的更快方法

C#保存位图的更快方法,c#,multithreading,bitmap,cpu,streamwriter,C#,Multithreading,Bitmap,Cpu,Streamwriter,我正在开发一个录音应用程序,我能够每秒获得10-15个屏幕截图。 问题是保存所有图像的速度要足够快,这样屏幕截图的队列就不会在RAM中累积并耗尽用户的内存 目前,我可以通过使用两个线程来实现这一点,这两个线程依次保存图像,然后收集垃圾 while (true) { bmp = null; Dispatcher.Invoke(new Action(delegate() { if (images.Count > 0) {

我正在开发一个录音应用程序,我能够每秒获得10-15个屏幕截图。 问题是保存所有图像的速度要足够快,这样屏幕截图的队列就不会在RAM中累积并耗尽用户的内存

目前,我可以通过使用两个线程来实现这一点,这两个线程依次保存图像,然后收集垃圾

while (true)
{
    bmp = null;

    Dispatcher.Invoke(new Action(delegate()
    {
        if (images.Count > 0)
        {
            bmp = images[0];
            images.RemoveAt(0);
        }
    }));

    if (bmp != null)
    {
        bmp.Save("frames\\" + framesImagesIndex++ + ".png", ImageFormat.Png);
        bmp.Dispose();
        bmp = null;
        GC.Collect();
    }

    Thread.Sleep(10);
}
问题是,它非常CPU密集,所以我认为它不会在性能较差的系统上工作。这个方法在我的3.31 GHz进程上需要30个CPU

当我将CPU设置为将所有图像写入一个文件,并通过锁定位图的位只写入字节时,我可以将CPU减少到17左右

byte[] rgbValues;

IntPtr ptr;

System.Drawing.Rectangle rect;

System.Drawing.Imaging.BitmapData bmpData;

System.Drawing.Imaging.PixelFormat pxf;


pxf = System.Drawing.Imaging.PixelFormat.Format24bppRgb;

//using(FileStream fs = new FileStream("frames.data", FileMode.OpenOrCreate, FileAccess.Write))
while (true)
{
    bmp = null;

    Dispatcher.Invoke(new Action(delegate()
    {
        if (images.Count > 0)
        {
            bmp = images[0];
            images.RemoveAt(0);
        }
    }));


    rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
    bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, pxf);

    ptr = bmpData.Scan0;

    rgbValues = new byte[bmpData.Stride * bmp.Height];

    Marshal.Copy(ptr, rgbValues, 0, rgbValues.Length);

    fs.Write(rgbValues, 0, rgbValues.Length);

    bmp.UnlockBits(bmpData);

    bmp.Dispose();
    bmp = null;
    GC.Collect();
}
这种方法有助于解决CPU问题,但因为速度不够快。图像队列会堆积并使ram过载,因此我不知道还能做些什么来解决这两个问题


还有其他可用的方法吗?

首先,使用
线程循环。Sleep(x)
非常占用CPU,就像
GC.Collect()
和频繁调用新实例一样。 您应该考虑使用线程

Action action;
public void Main()
{
action = new Action(delegate()
{
    if (images.Count > 0)
    {
        bmp = images[0];
        images.RemoveAt(0);
    }
});
Thread thread = new Thread(SaveBitmap());
thread.Start();
thread.Priority =  ThreadPriority.Highest
}
public void SaveBitmap()
{
    Dispatcher.Invoke(action);

if (bmp != null)
{
    bmp.Save("frames\\" + framesImagesIndex++ + ".png", ImageFormat.Png);
    bmp.Dispose();
    bmp = null;
}
}

尝试使用上面的方法,或者至少集成一些部分。

请记住,您在这个循环的每个迭代中都强制执行垃圾收集。。它是所有世代的完整收藏。当内存变大时,让GC负责清理内存可能会更好(而且这些位图没有根)。记住,GC在开始工作时会挂起所有线程。因此,当所有代都被收集起来,大型对象堆变得支离破碎时,所有东西实际上都停止在这条线上。我对它进行了测试,GC需要0到15毫秒,并且在删除它时不会减少CPU的使用。大部分时间都花在写文件上,即使。。这是一个你并不真正需要的延迟。CPU无疑会因为
而关闭,而(true)
。。您是否考虑过将文件写入工作委托给一些线程?或者这是在它自己的线程中运行的?与其专注于保存和清理,不如实施一种方法来限制收集过程?@Okuma.Scott,我不是在寻求帮助,以便在我的录音线程中添加睡眠呼叫。我请求帮助以更有效地保存15 FPS文件。我使用线程,我测试了2个和10个没有while循环的线程。