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?
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.