Delphi 10:正确同时运行任务的方法

时间:2017-07-12 22:53:30

标签: multithreading delphi task

我试图学习如何使用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个任务,每个应该在100ms内将其计数器增加1。然后我等待5秒并检查任务的值。我认为它们至少几乎相等,但真正的Memo1输出显示前12个值约为50,其他4个值约为20-30(我正在运行Ryzen 1600),对我来说有点奇怪最小的值都是0!

显然,40分钟中只有16个任务在5秒钟内完成了至少一次,所以我想知道如何将睡眠(100)替换为实际将执行传递给另一个任务?

1 个答案:

答案 0 :(得分:5)

仅仅因为您启动N个任务并不意味着N个任务将同时运行。如果您需要,请坚持使用TThread

PPL使用内部线程池来为TTask对象提供服务,并且该池是基于现在安装的许多CPU以及实际运行的任务数量而自我限制和自我调整的。这在PPL documentation

中有解释
  

RTL提供并行编程库(PPL),使您的应用程序能够并行运行任务,利用跨多个CPU设备和计算机的工作。 PPL包括许多高级功能,用于运行任务,加入任务,等待任务组等进行处理。 对于所有这些,有一个自动调整自身的线程池(基于CPU的负载),因此您不必关心为此目的创建或管理线程

如果创建的任务多于池有线程的任务,则某些任务将等待早期任务完成其工作。当给定线程完成任务时,它会检查等待任务,如果找到则运行它,重复直到没有更多任务要运行。乘以池中的线程数和队列中的任务数。

因此,在任何给定时间都只会运行少量任务,因此可能需要一段时间才能完成排队的所有任务。

如果想要更多地控制线程池,则必须创建一个TThreadPool对象,根据需要设置其MinWorkerThreadsMaxWorkerThreads属性,然后将该对象传递给其中一个具有TTask输入参数的APool构造函数。默认情况下,MinWorkerThreads设置为TThread.ProcessorCountMaxWorkerThreads设置为TThread.ProcessorCount * 25