【问题标题】:Why is OmniThreadLibrary's ForEach blocking main thread?为什么 OmniThreadLibrary 的 ForEach 会阻塞主线程?
【发布时间】:2013-06-02 06:46:54
【问题描述】:

使用 OmniThreadLibrary 和 Delphi XE4,我希望在后台运行多个线程来处理数据,从而提高我现有代码的速度。

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

【问题讨论】:

    标签: delphi delphi-xe4 omnithreadlibrary


    【解决方案1】:

    您必须将从 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中有记录。

    【讨论】:

    • 您能安排在任务完成时收到通知吗?
    • 谢谢。这更像是我自己的教育问题,因为我有你在我的召唤! ;-) 但我猜提问者可能想知道同样的事情。
    • @garb - 感谢您的快速回复。这解决了我的问题。顺便说一句,很棒的图书馆。带回 OTL 论坛,这样我就可以在那里问一百万个问题了 :)
    • 我现在在论坛上工作。出了点问题,但我还不知道为什么:(
    猜你喜欢
    • 1970-01-01
    • 2021-10-19
    • 2016-06-26
    • 1970-01-01
    • 2021-11-12
    • 2020-01-02
    • 2021-08-29
    • 1970-01-01
    相关资源
    最近更新 更多