Асинхронная загрузка буфера - PullRequest
2 голосов
/ 13 октября 2010

Intro:

У меня есть узкое место в моем приложении C #, где мне нужно загрузить страницу в виде растрового изображения из файла PDF или Tiff и обработать это растровое изображение, находясь в памяти.Файлы TIFF загружаются довольно быстро, как и PDF-файлы первых лиц (мы можем прочитать наши собственные).Узкое место возникает, когда файл PDF является сторонним, и нам нужно проанализировать страницу PDF и превратить ее в растровое изображение.Это дорого, в 500 раз медленнее, чем у оригинальных PDF-файлов.Некоторые из этих файлов 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 или структуры данных.
  • Дополнение : я бы хотел, чтобы оно было как можно более ленивым (загружать следующую страницу только при наличии местабесплатно в буфер

1 Ответ

0 голосов
/ 14 октября 2010

Это то, чем я закончил.Я хотел бы вместо того, чтобы опрашивать каждые 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);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...