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