异步缓冲区加载

时间:2010-10-13 14:16:23

标签: .net data-structures asynchronous

说明:

我的C#应用​​程序存在瓶颈,我需要将页面从PDF或Tiff文件加载为位图,并在内存中处理此位图。 Tiff文件加载速度相当快,以及第一方PDF(我们可以自己阅读)。当PDF文件是第三方并且我们需要解析PDF页面并将其转换为位图时,瓶颈就会出现。这是昂贵的,比第一方PDF慢500倍,以获得一个想法。其中一些PDF文件非常大,因此我们首先避免将整个文档加载到内存中。

假设:

在页面上完成的工作是在一个单独的过程中完成的(神奇地),而我的应用程序等待它完成。正因为如此,我相信如果我加载一个小缓冲区(一次说5页)异步它将加速这些第三方PDF文件的执行。

Psuedo(C#-ish):

IntPtr[] dibbuffer = new IntPtr[5];
dibbuffer[0] = LoadPage(0); //pre-emptive first page
BeginAsyncFillBuffer(dibbuffer);

for (i=0; i<NUM_PAGES; ++i)
{
    IntenseProcessing(dibbuffer[current_page_index_in_buffer]);
}

EndAsyncFillBuffer();

问题:

  • 这真的会加速吗? 应用? (它的一些机器 将运行单核)
  • 这是否值得尝试 对缓冲区进行同步和排序 处理线程?
  • 欢迎任何有关同步过程的提示。我正在使用C#,因此可以使用任何.Net约定或数据结构。
  • Adendum :我希望它尽可能地懒惰(只有当缓冲区中有空间时才加载下一页

1 个答案:

答案 0 :(得分:0)

这就是我最终的结果。我希望不是每X毫秒轮询它更“懒惰”,只在需要时填充单独线程上的缓冲区。如果有人可以改进这一点,请做。

class MyGhettoBuffer
{
    Target _target = null; //contains info on the file @ hand
    Queue _q = null;
    Queue _synchQ = null;
    Thread _loop = null;
    ManualResetEvent _throttle = new ManualResetEvent(false);
    int _curpage = 0;

    private MyGhettoBuffer() { }
    public MyGhettoBuffer(Target target)
    {
        _target = target;
        _q = new Queue();
        _synchQ = Queue.Synchronized(_q);
        _loop = new Thread(MainLoop);
        _loop.Start();
    }

    public bool HasPagesLeft //determine when to stop processing queue
    {
        get
        {
            if (_curpage >= _target.NumPages &&
                _synchQ.Count == 0)
                return false;
            else
                return true;
        }
    }
    //if the buffer hasnt caught up load the page on the processing thread
    public IntPtr GetNextPage()
    {
        lock (this)
        {
            if (_synchQ.Count == 0) 
            {
                IntPtr dib =
                    LoadDib(_target.FullPath, _curpage);
                _curpage++;
                return dib;
            }
            else
            {
                object o = _synchQ.Dequeue();
                if (o is IntPtr)
                {
                    return (IntPtr)o;
                }
                else
                {
                    throw new InvalidCastException("Object in page queue is not an IntPtr");
                }
            }
        }
    }

    private void MainLoop()
    {
        while (true)
        {
            if (_curpage < _target.NumPages)
            {
                if (_synchQ.Count < 5)
                {
                    lock (this)
                    {
                        IntPtr dib =
                            LoadDib(_target.FullPath, _curpage);
                        _synchQ.Enqueue(dib);
                        _curpage++;
                    }
                }
            }
            else
            {
                return;
            }
            _throttle.WaitOne(100, false); //dont use a %@#! ton of cpu cycles
        }
    }
}

然后,在我的处理线程中,我做了类似的事情:

MyGhettoBuffer buffer = new MyGhettoBuffer(target);
while (buffer.HasPagesLeft)
{
    IntPtr dib = GetNextPage();
    //Process the dib here
    FreeDib(dib);
}