【发布时间】:2014-11-14 21:34:37
【问题描述】:
我想使用 Delphi XE7 的新并行库并行处理一个耗时的例程。
这里是单线程版本:
procedure TTerritoryList.SetUpdating(const Value: boolean);
var
i, n: Integer;
begin
if (fUpdating <> Value) or not Value then
begin
fUpdating := Value;
for i := 0 to Count - 1 do
begin
Territory[i].Updating := Value; // <<<<<< Time consuming routine
if assigned(fOnCreateShapesProgress) then
fOnCreateShapesProgress(Self, 'Reconfiguring ' + Territory[i].Name, i / (Count - 1));
end;
end;
end;
真的没有什么复杂的事情发生。如果更改了区域列表变量或将其设置为 false,则例程会循环所有销售区域并重新创建区域边界(这是一项耗时的任务)。
所以这是我尝试使其平行:
procedure TTerritoryList.SetUpdating(const Value: boolean);
var
i, n: Integer;
begin
if (fUpdating <> Value) or not Value then
begin
fUpdating := Value;
n := Count;
i := 0;
TParallel.For(0, Count - 1,
procedure(Index: integer)
begin
Territory[Index].Updating := fUpdating; // <<<<<< Time consuming routine
TInterlocked.Increment(i);
TThread.Queue(TThread.CurrentThread,
procedure
begin
if assigned(fOnCreateShapesProgress) then
fOnCreateShapesProgress(nil, 'Reconfiguring ', i / n);
end);
end
);
end;
end;
我已将 for 循环替换为并行 for 循环。计数器“i”在递增以显示进度时被锁定。然后,我将 OnCreateShapeProgress 事件包装在 TThread.Queue 中,由主线程处理。 OnCreateShapeProgress 事件由更新进度条和描述任务的标签的例程处理。
如果我排除对 OnCreateShapeProgress 事件的调用,该例程将起作用。它会因 EAurgumentOutOfRange 错误而崩溃。
所以我的问题很简单:
我做了什么蠢事吗?
如何从 TParallel.For 循环或 TTask 中调用事件处理程序?
【问题讨论】:
-
TParallel.For在 XE7 中有一个错误,已在更新 1 中修复。我认为它在这里没有任何意义,但无论如何都要测试更新。见TParallel.For reserves, but not frees memory。
标签: multithreading delphi parallel-processing tthread