为什么OmniThreadLibrary的ForEach阻塞主线程? [英] Why is OmniThreadLibrary's ForEach blocking main thread?

查看:322
本文介绍了为什么OmniThreadLibrary的ForEach阻塞主线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Using the OmniThreadLibrary and Delphi XE4, I am hoping to run multiple threads that process data in the background, adding speed increases to my already existing code.

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

When calling the procedure below, the Application GUI stops processing any input until all of the threads have completed. My understanding is that using .NoWait should allow the procedure to exit even when the threads are running.

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的任何建议都是值得赞赏的。

Is my understanding of the ForEach loop incorrect, suggesting I should use an alternate method to achieve background processing? Any suggestions on the correct use of the OmniThreadLibrary is appreciated.

推荐答案

你必须存储从Parallel.ForEach返回的界面一个全局(form etc)变量,只有当ForEach完成执行时才会销毁它。

You have to store the interface returned from the Parallel.ForEach in a global (form etc) variable and destroy it only when the ForEach finishes execution.

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

In your example, the result of ForEach is stored in a temporary variable which is destroyed when the Test procedure exits. The ForEach destructor waits for all tasks to complete and that blocks your program.

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

The safest (but admittedly non-obvious) way to destroy the foreach interface on task completion is to use the OnStop method and from it queue a command to the main thread.

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);

这被记录在维基

这篇关于为什么OmniThreadLibrary的ForEach阻塞主线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆