stacker_liew 5 Posted May 6, 2023 I have two program, one is using TParallel, the other is using TTask, both do the same thing, but TParallel version is far more fast than TTask version, does it true? Here is TParallel Version, Elapsed Time 10ms: procedure TSingleThreadTestForm.SingleThreadTestClickToStartThreadButtonClick(Sender: TObject); var SumValue: Int64; TempStopWatch: TStopWatch; begin SumValue := 0; TempStopWatch := TStopWatch.Create; TempStopWatch.Start; (Sender as TButton).Enabled := False; try TParallel.For(1000, 0, Pred(1000000), procedure(I: Int64) begin TInterlocked.Increment(SumValue); end); TempStopWatch.Stop; finally (Sender as TButton).Enabled := True; SingleThreadTestResultLabel.Caption := 'Process Result: ' + SumValue.ToString; SingleThreadTestElapsedTimeLabel.Caption := 'Elapsed Time: ' + TempStopWatch.ElapsedMilliseconds.ToString + ' ms'; end; end; Here is TTask Version, Elasped Time 50ms: procedure TMultiThreadTestForm.MultiThreadTestClickToStartThreadButtonClick(Sender: TObject); var I, SumValue: Int64; Tasks: TArray<ITask>; TempStopWatch: TStopWatch; begin SumValue := 0; TempStopWatch := TStopWatch.Create; TempStopWatch.Start; SetLength(Tasks, 1000); (Sender as TButton).Enabled := False; try for I := 0 to Pred(Length(Tasks)) do begin Tasks[I] := TTask.Create( procedure() var ThreadedI: Integer; ISum: Integer; begin ISum := 0; for ThreadedI := 0 to Pred(1000000) do begin Inc(ISum); end; TInterlocked.Add(SumValue, ISum); end); end; for I := 0 to Pred(Length(Tasks)) do Tasks[I].Start; // Start Created Thread TTask.WaitForAll(Tasks); TempStopWatch.Stop; finally (Sender as TButton).Enabled := True; MultiThreadTestResultLabel.Caption := 'Process Result: ' + SumValue.ToString; MultiThreadTestElapsedTimeLabel.Caption := 'Elapsed Time: ' + TempStopWatch.ElapsedMilliseconds.ToString + ' ms'; end; end; Share this post Link to post
Cristian Peța 103 Posted May 8, 2023 TParallel.For will not start 1000 threads so fast like a for loop but will use a thread pool and wait for a thread to finish before starting an other. Share this post Link to post
Dalija Prasnikar 1396 Posted May 8, 2023 On 5/6/2023 at 5:40 PM, stacker_liew said: I have two program, one is using TParallel, the other is using TTask, both do the same thing, but TParallel version is far more fast than TTask version, does it true? Those two methods you have don't do the same thing. If you take a look to the result of the calculation, you will see that results are different. First method will increment sum 1000000 times and second will increment temporary value 1000000 times and then add that temporary result to the total sum 1000 times. So the second method runs more operations and that is why it runs slower. If you correct the code to calculate exactly the same sum in the second method, you will see that this one will run faster. for ThreadedI := 0 to Pred(1000) do begin Inc(ISum); end; Number of tasks running in both cases will be the same, but the second method has the advantage because the temporary calculation is not using interlocked operation which is costly, and only uses it to add that temporary sum to the final result. Overall, Parallel.For code will run interlocked operation 1000000 times, and task based method only 1000 times. 3 Share this post Link to post
stacker_liew 5 Posted May 8, 2023 5 hours ago, Dalija Prasnikar said: Those two methods you have don't do the same thing. If you take a look to the result of the calculation, you will see that results are different. First method will increment sum 1000000 times and second will increment temporary value 1000000 times and then add that temporary result to the total sum 1000 times. So the second method runs more operations and that is why it runs slower. If you correct the code to calculate exactly the same sum in the second method, you will see that this one will run faster. for ThreadedI := 0 to Pred(1000) do begin Inc(ISum); end; Number of tasks running in both cases will be the same, but the second method has the advantage because the temporary calculation is not using interlocked operation which is costly, and only uses it to add that temporary sum to the final result. Overall, Parallel.For code will run interlocked operation 1000000 times, and task based method only 1000 times. I see, thanks, now the TTask version elapsed time change to 3ms. Share this post Link to post
stacker_liew 5 Posted May 9, 2023 It looks like normal for loop is faster than TParallel.For here. Share this post Link to post
Dalija Prasnikar 1396 Posted May 9, 2023 1 hour ago, stacker_liew said: It looks like normal for loop is faster than TParallel.For here. Yes, because interlocked operation are expensive. Multithreading always comes at a price. The code is more complicated, you need to pay attention to thread safety and it will generally run slower than single threaded code. Not every operation is worth doing in parallel. If some calculation takes longer time, you can run it in single background thread, so you can keep your application responsive, but for splitting some task to multiple threads, you need to make sure that the task can be successfully parallelized and that performance gained is significant enough. For any operation that runs less than a second, it is usually not even worth to start a single background thread, let alone starting multiple ones. 1 Share this post Link to post
Stefan Glienke 2002 Posted May 9, 2023 As Dalija already mentioned some things that you need to do in a parallel environment add some overhead. This means that when the actual workload you are doing (such as incrementing a number) is so small that added overhead dominates the overall time. We all can agree that incrementing a number is not a suitable task to be executed in parallel. However, if you were to do some real-world tasks in parallel, there are still some things to consider - such as what has been discussed some while ago on StackOverflow, namely partitioning of data to process it in parallel properly. 1 Share this post Link to post