我正在尝试学习如何使用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 对象,根据需要设置其MinWorkerThreadsMaxWorkerThreads属性,然后将该对象传递给具有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/

10-12 23:51