如何使TParallel.& For循环响应并将值存储在TList< T>中? [英] How to make a TParallel.&For loop responsive and store values in a TList<T>?
问题描述
在Delphi 10.1 Berlin中,我想使TParallel.&For
循环响应.
In Delphi 10.1 Berlin I would like to make a TParallel.&For
loop responsive.
I have a parallel loop similar to the example in question TParallel.For: Store values in a TList while they are calculated in a TParallel.For loop . The loop calculates values and stores these values in a TList<Real>
.
我尝试使用TTask.Run
在单独的线程中运行TParallel.&For
,以使其具有响应性:
I try to run the TParallel.&For
in 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 incorrect 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
....
我也尝试了Synchronize
TThread.Synchronize(TThread.Current,
procedure
begin
List.Add(Res);
end
);
或
TThread.Synchronize(nil,
procedure
begin
List.Add(Res);
end
);
和Queue
TThread.Queue(TThread.Current,
procedure
begin
List.Add(Res);
end
);
或
TThread.Queue(nil,
procedure
begin
List.Add(Res);
end
);
但是问题仍然存在.我在做什么错了?
but the problem remains. What am I doing wrong?
推荐答案
Parallel.For
循环中的所有线程都共享Res
变量.当线程要将Res
值存储到列表中时,一个或多个线程可能已经对其进行了更改.换句话说,Res
的值在放入列表时是不可预测的.
All threads in the Parallel.For
loop shares the Res
variable. When a thread is about to store the Res
value into the list, it could already have been altered by one or many threads. In other words, the value of Res
is unpredictable at the time of putting it into the list.
通过在每个线程中本地设置Res
来修复该问题.
Fix it by making Res
local to each thread.
关于哪种方法最好,我建议进行性能比较. @Ken的建议似乎也是一个不错的主意.避免锁定通常是提高性能的秘诀.
As for which method is the best, I suggest to make a performance comparison. And the suggestion by @Ken seems like a good idea to try as well. Avoiding locks is often a recipe for good performance.
此外,还要与没有线程的循环进行比较.
Also, compare against a loop without threads as well.
这篇关于如何使TParallel.& For循环响应并将值存储在TList< T>中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!