Delphi TThreadPool:在继续代码之前等待空闲线程槽

Posted

技术标签:

【中文标题】Delphi TThreadPool:在继续代码之前等待空闲线程槽【英文标题】:Delphi TThreadPool: wait for free thread slot before proceeding with code 【发布时间】:2021-05-06 18:35:48 【问题描述】:

我知道TTask并成功使用TTask.WaitForAll(array),以及TParallel.&For()

但是现在想做一个看似简单的事情却不知道怎么做:

我有未知数量的物品进来,这可能是数百万或只有几件,而且我不提前知道。如何在没有队列的情况下并行处理它们(大约 4 个线程左右)?如果最大线程已经很忙,我想等待下一个空闲槽。像 TTask.Run() 这样的东西,直到它真正开始运行才会回来。

我想我只是在监督一些简单的事情......?

当我完成后,我想等待所有剩余的任务完成。但我当然不想将数百万个数组放在WaitForAll() 的数组中。


我可以想象一个可能的解决方案(但我不喜欢它,希望使用TTask 或类似的方法更简单):

将工作推送到TThreadedQueue,如果队列已满,它会自动让我等待 启动 4 个线程并让它们循环从该队列中弹出

我知道在某些情况下这可能是首选方式,但我的情况不会从中受益(例如重用任何对象、连接等)。


伪代码变得又好又干净:

MyThreadPool:= TMyThreadPool.Create(4);
while GetNextItem(out Item) do
  //the following comes back when it has really been started:
  MyThreadPool.Run(procedure begin Work(Item); end);
MyThreadPool.WaitFor;

【问题讨论】:

你只有两个选择。为每条记录创建一个TTask 并让TThreadPool 为您处理限制,或者您将记录排队并自己限制它们。线程安全队列可以正常工作,并且仍然允许您重用对象。这只是你如何为它们编写逻辑的问题。我会使用记录对象池、连接对象轮询等。拉出记录,填充它,将其放入队列中。当一个线程从队列中拉出记录时,拉出一个连接并使用它,然后将记录和连接推回它们的池中。重复直到队列为空 嗨@RemyLebeau,因为它与数据库记录无关(在这种情况下我正在处理文件),所以我没有什么可以重用的。所以我希望有一些简单而简短的代码,比如TParallel.@For。还有什么想法吗?我可以得到内部 TTask 队列的大小吗? 有趣的相关问题:***.com/questions/51571759/… 【参考方案1】:

这似乎是一个可行的解决方案,但滥用TParallel.&For 可能不是很好。我仍然希望得到更好的答案。

if FindFirst(Path, 0, SearchRec) = 0 then
  try
    TParallel.&For(0, 99999,
      procedure(I: Integer; LoopState: TParallel.TLoopState)
      var
        Filename: string;
      begin
        if LoopState.ShouldExit then Exit;

        TMonitor.Enter(Self);
        try
          Filename:= SearchRec.Name;
          if (FindNext(SearchRec) <> 0) or TThread.CheckTerminated then
            LoopState.Stop; //or .Break?
        finally
          TMonitor.Exit(Self);
        end;

        try
          ProcessFile(Filename);
        except
          on E: Exception do Log(E.ToString); //maybe also want to Stop
        end;
      end);
  finally
    FindClose(SearchRec);
  end;

我写了很多跟踪日志,看起来不错。唯一不好的是,在最后一个文件之后,它仍然会开始 10-20 多个执行,然后在开始时退出。

似乎默认线程池不能限制为少于处理器数量。

如果您认为有什么不好或可以/应该改进的地方,请发表评论。

【讨论】:

以上是关于Delphi TThreadPool:在继续代码之前等待空闲线程槽的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Delphi 中使用复选框?

delphi 2010 没有QuickRpt问题

Delphi 设计模式:《HeadFirst设计模式》Delphi7代码---工厂模式之简单工厂

Delphi2007:在调试器中继续暂停应用程序时崩溃

Delphi Code Editor 之 几个特性

启动终端程序,但在终端关闭后继续运行 - Lazarus 或 Delphi