2013-06-02 21 views
2

使用OmniThreadLibrary和Delphi XE4,我希望运行多个线程来处理后台数据,为我现有的代码增加速度。为什么OmniThreadLibrary的ForEach阻止主线程?

当调用下面的过程时,应用程序GUI将停止处理任何输入,直到所有线程都完成为止。我的理解是,即使线程正在运行,使用.NoWait也应允许该过程退出。

procedure Test(input: TStringList; output: TList<TMaintFore>); 
var 
    outQueue: IOmniBlockingCollection; 
    transaction: TOmniValue; 
begin 
    outQueue := TOmniBlockingCollection.Create; 
    Parallel.ForEach(0, input.Count - 1) 
    .NoWait 
    .Into(outQueue) 
    .Execute(
     procedure(const value: integer; var result: TOmniValue) 
     begin 
     result := TMaintFore.Create(input[value]); 
     end 
    ); 
end; 

我对ForEach循环的理解不正确,提示我应该使用其他方法来实现后台处理?任何关于正确使用OmniThreadLibrary的建议,我都赞赏。

回答

10

您必须将从Parallel.ForEach返回的接口存储在全局(表单等)变量中,并且只有在ForEach完成执行时才将其销毁。

在您的示例中,ForEach的结果存储在临时变量中,该变量在测试过程退出时被销毁。 ForEach析构函数等待所有任务完成并阻止您的程序。

在任务完成时销毁foreach接口的最安全(但不言而喻)的方式是使用OnStop方法,并从中将命令排队到主线程。

var 
    loop: IOmniParallelLoop<integer>; 

loop := Parallel.ForEach(1, N).NoWait; 
loop.OnStop(
    procedure (const task: IOmniTask) 
    begin 
    task.Invoke(
     procedure 
     begin 
     // do anything 
     loop := nil; 
     end); 
    end); 
loop.Execute(
    procedure (const value: integer) 
    begin 
    ... 
    end); 

这记录在the wiki

+1

您可以安排在任务完成时收到通知吗? –

+0

回答上面。 – gabr

+1

谢谢。这对我自己的教育来说更是一个问题,因为我看到你在我的支持和呼唤! ;-)但我猜想提问者可能会好奇同样的事情。 –