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:在继续代码之前等待空闲线程槽的主要内容,如果未能解决你的问题,请参考以下文章