2012-02-12 2 views
6

Я никогда не использовал нити - никогда не думал, что мой код принесет пользу. Тем не менее, я думаю, нарезания резьбы может улучшить производительность следующего псевдокода:Threading for Performance Improvement

Loop through table of records containing security symbol field and a quote field 
    Load a web page (containing a security quote for a symbol) into a string variable 
    Parse the string for the quote 
    Save the quote in the table 
    Get next record 
end loop 

Загрузка каждой веб-страницы занимает больше всего времени. Разбор для цитаты довольно быстр. Наверное, я мог бы взять, скажем, половину записей для одного потока, а другую - вторую.

+1

Используйте рамки потоковая, которые вы можете найти ссылки на многочисленные вопросы в StackOverflow (сделайте поиск) – Misha

+5

Заканчивать: http://www.thedelphigeek.com/2011/10/omnithreadlibrary-in-practice- 1web.html – gabr

+1

Я бы пошел с omnithreadlibrary, это очень продуктивно, кстати. посмотрите также на omnixml, эти библиотеки чрезвычайно полезны! – ComputerSaysNo

ответ

4

В OmniThreadLibrary очень просто решить эту проблему с помощью многоступенчатого конвейера - первый этап запускается по нескольким задачам и загружает веб-страницы и выполняет второй этап в одном экземпляре и сохраняет данные в базе данных. Я написал документ blog post, документирующий это решение некоторое время назад.

Решение можно суммировать с помощью следующего кода (вам нужно будет заполнить некоторые места в методах HttpGet и Inserter).

uses 
    OtlCommon, 
    OtlCollections, 
    OtlParallel; 

function HttpGet(url: string; var page: string): boolean; 
begin 
    // retrieve page contents from the url; return False if page is not accessible 
end; 

procedure Retriever(const input: TOmniValue; var output: TOmniValue); 
var 
    pageContents: string; 
begin 
    if HttpGet(input.AsString, pageContents) then 
    output := TPage.Create(input.AsString, pageContents); 
end; 

procedure Inserter(const input, output: IOmniBlockingCollection); 
var 
    page : TOmniValue; 
    pageObj: TPage; 
begin 
    // connect to database 
    for page in input do begin 
    pageObj := TPage(page.AsObject); 
    // insert pageObj into database 
    FreeAndNil(pageObj); 
    end; 
    // close database connection 
end; 

procedure ParallelWebRetriever; 
var 
    pipeline: IOmniPipeline; 
    s  : string; 
    urlList : TStringList; 
begin 
    // set up pipeline 
    pipeline := Parallel.Pipeline 
    .Stage(Retriever).NumTasks(Environment.Process.Affinity.Count * 2) 
    .Stage(Inserter) 
    .Run; 
    // insert URLs to be retrieved 
    for s in urlList do 
    pipeline.Input.Add(s); 
    pipeline.Input.CompleteAdding; 
    // wait for pipeline to complete 
    pipeline.WaitFor(INFINITE); 
end; 
4

Если количество записей относительно мало, скажем, 50 или меньше, вы можете просто запустить отдельный поток для каждой записи, и пусть они все работают параллельно, например:

begin thread 
    Load a web page for symbol into a string variable 
    Parse the string for the quote 
    Save the quote in the table 
end thread 

.

Loop through table of records 
    Launch a thread for current security symbol 
    Get next record 
end loop 

Если у вас есть большее количество записей в процессе, рассмотреть возможность использования пула потоков, так что вы можете обрабатывать записи в небольших партий, например:

Create X threads 
Put threads in a list 

Loop through table of records 
    Wait until a thread in pool is idle 
    Get idle thread from pool 
    Assign current security symbol to thread 
    Signal thread 
    Get next record 
end loop 

Wait for all threads to be idle 
Terminate threads 

.

begin thread 
    Loop until terminated 
    Mark idle 
    Wait for signal 
    If not Terminated 
     Load a web page for current symbol into a string variable 
     Parse the string for the quote 
     Save the quote in the table 
    end if 
    end loop 
end thread 

Существует много разных способов реализации вышеизложенного, поэтому я оставил его в псевдокоде. Посмотрите классы , TList и TEvent, или функцию Win32 API QueueUserWorkerItem(), или любое количество сторонних библиотек потоков.

+1

Я думаю, что решение, основанное на трубопроводах, здесь более уместно, так как составные части задач совершенно разные по своей природе. Вытягивание загрузки связано с привязкой IO и разборчивость файла связана с ЦП. –

+0

@ Давид: Мне нужно провести некоторое исследование «конвейерной обработки», потому что я никогда не слышал об этом. Хорошие ссылки на ссылки будут оценены по достоинству. –

+0

websearch выполнит работу –