Search code examples
multithreadingdelphidelphi-10.2-tokyo

TTask slower than TThread


I have below two methods of multi-threading code doing the same job.

TTask:

const
  MaxThreadCount = 80;

procedure TWorkerTask.Update;
var
  aTasks  : array of ITask;
  I: Integer;
begin
  Stopwatch := TStopwatch.StartNew;
  SetLength(aTasks, MaxThreadCount);
  for I := Low(aTasks) to High(aTasks) do begin
    aTasks[I] := TTask.Create( procedure
    begin
      Writeln('Thread ', TTask.CurrentTask.Id, ' Stared');
      Sleep(5000);
      Writeln('Thread ', TTask.CurrentTask.Id, ' Finshed');
    end);
    aTasks[I].Start;
  end;
  TTask.WaitForAll(aTasks);
  Elapsed := Stopwatch.Elapsed;
  Writeln('Done in ', Round(Elapsed.TotalSeconds));
end;

Output e.g Done in 29

TThread:

const
  MaxThreadCount = 80;

procedure TWorker.Execute;
begin
  Writeln('Thread ', ThreadID, ' Stared');
  Sleep(5000);
  Writeln('Thread ', ThreadID, ' Finshed');
end;

....

var
  Workers   : array of TWorker;
  I         : Integer;
  Stopwatch : TStopwatch;
  Elapsed   : TTimeSpan;  
begin
  SetLength(Workers, MaxThreadCount);
  for I := Low(Workers) to High(Workers) do begin
    Workers[I] := TWorker.Create;
    Workers[I].Start;
  end;
  for I := Low(Workers) to High(Workers) do
    Workers[I].WaitFor;
  Elapsed := Stopwatch.Elapsed;
  Writeln('Done ', Round(Elapsed.TotalSeconds));

Output e.g Done 8

Q: Why the TTask is extremely slower than the TThread class on the above method? Is there a way to speed it up to get similar result?


Solution

  • It's because your threads and tasks do no work.

    You have more threads than processors. In the version using threads, you can create one thread per task and although the processors are oversubscribed, that doesn't matter because the threads are sleeping.

    In the task based version there is, typically, one thread per processor. So not all tasks can run simultaneously.

    Were you to replace the sleep with busy work running the CPU at full utilisation then you would see that both versions performed similarly. Indeed I would expect the task based version to be better since it would not oversubscribe the processors.