Jump to content
stacker_liew

TParallel Version and TTask Version

Recommended Posts

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

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

  • Like 3

Share this post


Link to post
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
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.

 

  • Like 1

Share this post


Link to post

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.

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×