我从未使用过线程 - 从未想过我的代码会受益。但是,我认为线程可能会提高以下伪代码的性能:
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
加载每个网页需要花费大量时间。解析报价非常快。我想我可以拿一个线程的一半记录,然后在另一个线程中处理另一半。
答案 0 :(得分: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
有许多不同的方法可以实现上述功能,这就是我将其保留为伪代码的原因。查看VCL的TThread
,TList
和TEvent
类,或Win32 API QueueUserWorkerItem()
函数或任意数量的第三方线程库。
答案 1 :(得分: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;