为什么OmniThreadLibrary的ForEach阻塞主线程?

时间:2013-06-02 06:46:55

标签: delphi delphi-xe4 omnithreadlibrary

使用OmniThreadLibrary和Delphi XE4,我希望运行多个在后台处理数据的线程,为我现有的代码增加速度。

调用下面的过程时,Application 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的任何建议都表示赞赏。

1 个答案:

答案 0 :(得分:10)

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

在您的示例中,ForEach的结果存储在临时变量中,该变量在Test过程退出时被销毁。 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中记录了这一点。