Reputation: 2320
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?
Upvotes: 4
Views: 2511
Reputation: 681
Each task does not necessarily mean 1 thread. The delphi tasks system saves resources, and even monitors CPU usage to decide whether to create more threads or not. Particularly I also find the task slow, and to avoid this slowness, when I need to use task I simply create a threadpool for each task, so it will have the same performance as a simple TThread because that way you will ensure that each task will run on own thread.
You can try something like this:
TTask.Run(
procedure()
begin
end, TThreadPool.Create);
Upvotes: 0
Reputation: 612794
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.
Upvotes: 8