我正在尝试学习如何使用delphi并行库而不是TThread。我有许多要同时运行的任务。每个任务最多都是在等待某个事件,而在等待时,我想将执行权传递给其他任务。
这是我的示例代码:
type
TObj = class
pos: integer;
Done: boolean;
Constructor Create;
procedure DoWork(Sender: TObject);
end;
var
Objects : array [0..39] of TObj;
tasks : array of ITask;
constructor TObj.Create;
begin
pos:=0;
DOne:=false;
end;
procedure TObj.DoWork(Sender: TObject);
begin
repeat
inc(pos);
sleep(100);
until Done;
end;
procedure TForm1.StartClick(Sender: TObject);
var
i: integer;
begin
Setlength (tasks ,Length(Objects));
for i:=0 to Length(tasks)-1 do begin
Objects[i]:=TObj.Create;
tasks[i] := TTask.Create(Objects[i],Objects[i].DoWork);
tasks[i].Start;
end;
sleep(5000);
Memo1.Lines.Clear;
for i:=0 to Length(tasks)-1 do begin
Objects[i].Done:=true;
Memo1.Lines.Add(IntToStr(Objects[i].pos));
end;
end;
我启动了N个任务,每个任务应在100毫秒内将其计数器增加1。然后我等待5秒钟,然后检查任务的值。我期望它们至少几乎相等,但是实际的Memo1的输出显示前12个值大约为50,其他4个值大约为20-30(我正在运行Ryzen 1600),我感到奇怪的是,最小的值都是0!
显然,在40秒中,至少有40个任务中有16个任务在5秒内一次被执行了,所以我想知道如何替换sleep(100)来将执行权实际传递给另一个任务?
最佳答案
仅仅因为您启动了N个任务,并不意味着N个任务将同时运行。如果需要,请坚持使用TThread
。
PPL使用内部线程池为TTask
对象提供服务,并且该池根据您已安装的许多CPU和实际运行的任务数量进行自我调节。这在PPL documentation中进行了解释:
如果创建的任务多于池中具有线程的任务,则某些任务将等待较早的任务完成其工作。当给定线程完成任务时,它将检查等待的任务,如果找到则运行该任务,然后重复进行直到没有其他任务可以运行为止。将其乘以池中的线程数和队列中的任务数。
因此,在任何给定时间都只会运行少量任务,因此可能要花一些时间才能完成所有排队的任务。
如果要对线程池进行更多控制,则必须创建一个 TThreadPool
对象,根据需要设置其MinWorkerThreads
和MaxWorkerThreads
属性,然后将该对象传递给具有TTask
输入参数的APool
构造函数之一。默认情况下,MinWorkerThreads
设置为TThread.ProcessorCount
,并且MaxWorkerThreads
设置为TThread.ProcessorCount * 25
。
关于multithreading - Delphi 10 : Correct way to run tasks simultaneously,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45068750/