multithreading - 德尔福TThreadPool : wait for free thread slot before proceeding with code

标签 multithreading delphi parallel-processing threadpool delphi-10.3-rio

我了解 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;

最佳答案

这似乎是一个有效的解决方案,但滥用 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 次以上的执行,然后在开始时退出。

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

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

关于multithreading - 德尔福TThreadPool : wait for free thread slot before proceeding with code,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66012106/

相关文章:

c++ - pthread_exit(NULL);不工作

xml - 当 responseText 包含有效的 Xml 时,IXMLHttpRequest.responseXml 为空,没有解析错误

delphi - 如何根据嵌套数据集记录数过滤数据集?

multithreading - 处理Akka actor的receive方法中的异步调用的最佳方法

perl - 杀死进程本身和所有子进程的最佳方法

c# - N 个线程异步获取/执行任务

linux - 如何使用多线程进行 zlib 压缩(相同输入源)

android - 使用 RxJava 限制吞吐量

c++ - 从 Delphi 应用程序调用时,如何修复 C++ DLL 中 MessageBox 中显示的无效字符?

r - Snow结束后是否需要移除导出的变量