How to set up TPalallel. & For, react and store values โโin TList <T>?
In Delphi 10.1 Berlin, I would like to make the loop TParallel.&For
responsive.
I have a parallel loop similar to the TParallel.For example in question: Store values โโin a TList as they are computed in a TParallel.For loop . The loop calculates the values โโand stores those values โโin TList<Real>
.
I am trying to run TParallel.&For
on a separate thread with TTask.Run
to make it responsive:
type
TCalculationProject=class(TObject)
private
Task: ITask;
...
public
List: TList<Real>;
...
end;
function TCalculationProject.CalculateListItem(const AIndex: Integer): Real;
begin
//a function which takes a lot of calculation time
//however in this example we simulate the calculation time and
//use a simple alogorithm to verify the list afterwards
Sleep(30);
Result:=10*AIndex;
end;
procedure TCalculationProject.CalculateList;
begin
List.Clear;
Task:=TTask.Run(
procedure
var
LoopResult: TParallel.TLoopResult;
Res: Real;
Lock: TCriticalSection;
begin
Lock:=TCriticalSection.Create;
try
LoopResult:=TParallel.&For(0, 1000-1,
procedure(AIndex: Integer; LoopState: TParallel.TLoopState)
begin
Res:=CalculateListItem(AIndex);
Lock.Enter;
try
List.Add(Res);
finally
Lock.Leave;
end;
end
);
finally
Lock.Free;
end;
if LoopResult.Completed then
begin
TThread.Synchronize(TThread.Current,
procedure
begin
SortList;
ShowList;
end
);
end;
end
);
end;
The problem is that the list is wrong on a random basis: there are duplicate values โโin the list. For example:
list item 0: 0
list item 1: 10
list item 2: 20
list item 3: 20 <- incorrect
list item 4: 20 <- incorrect
list item 5: 50
....
Instead of a part, Lock.Enter
Lock.Leave
I also triedSynchronize
TThread.Synchronize(TThread.Current,
procedure
begin
List.Add(Res);
end
);
or
TThread.Synchronize(nil,
procedure
begin
List.Add(Res);
end
);
and Queue
TThread.Queue(TThread.Current,
procedure
begin
List.Add(Res);
end
);
or
TThread.Queue(nil,
procedure
begin
List.Add(Res);
end
);
but the problem remains. What am I doing wrong?
source to share
All threads in the loop Parallel.For
share a variable Res
. When a thread is about to store a value Res
in the list, it may already have been modified by one or more threads. In other words, the value is Res
unpredictable as it is entered into the list.
Fix it by making it Res
local to each thread.
As for which method is the best, I suggest comparing performance. And @Ken's suggestion seems like a good idea to give it a try. Blocking prevention is often a recipe for good performance.
Also, compare to a loop without threads.
source to share