Multithreading 使用delphixe7并行库

Multithreading 使用delphixe7并行库,multithreading,delphi,parallel-processing,tthread,Multithreading,Delphi,Parallel Processing,Tthread,我有一个耗时的例程,我想使用DelphiXe7新的并行库并行处理它 以下是单线程版本: 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 b

我有一个耗时的例程,我想使用DelphiXe7新的并行库并行处理它

以下是单线程版本:

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;
过程TTERITORYLIST.SetUpdating(常量值:布尔值);
变量
i、 n:整数;
开始
如果为(更新值)或非值,则
开始
fUpdating:=值;
对于i:=0进行计数-1 do
开始

地域[i]。更新:=值;// 我能看到的最明显的问题是,您排队等待工作线程

TThread.Queue
的调用将传递
TThread.CurrentThread
。这就是您正在调用
TThread.Queue
的线程。我认为可以肯定地说,您不应该将
TThread.CurrentThread
传递到
TThread.Queue

相反,请删除该参数。使用仅接受线程过程的单参数重载

否则,我会注意到进度计数器
I
的递增并没有真正正确处理。好吧,递增是可以的,但是你稍后再读它,那就是一场竞赛。如果线程1在线程2之前递增,但线程2在线程1之前对进度进行排队,则可以按顺序报告进度。通过将计数器增量代码移动到主线程来解决这个问题。只需在排队的匿名方法中增加它。额外的好处是,您不再需要使用原子增量,因为所有修改都在主线程上

除此之外,本质量控制报告似乎与您的报告非常相似:


最后,
AtomicIncrement
是在最新版本的Delphi中执行无锁增量的惯用方法

TParallel.For
在XE7中有一个bug,该bug在更新1中修复。我不认为它在这里有任何意义,但无论如何都要用更新进行测试。看,谢谢大卫,这很有帮助。传递
TThread.CurrentThread
是Danny Wind在最近的Coderage 9演讲(21分钟25秒)中所做的。我同意这似乎不正确。当我将其更改为
nil
时,它不会崩溃,但不会显示进度条。当我将
TThread.Queue
更改为
TThread.Syncronize
时,会出现
eargumentootfrange
错误。似乎在使用
TThread,Queue
时,代码仅在例程完成后执行(这有一定意义)。因此,更改为
TThread.Syncronize应该可以解决这个问题,但我仍然得到了错误。您应该使用队列的单参数重载。也许这是一个Delphi错误。坦白地说,我不相信Emba-rtl开发人员会建立一个线程库。他们在这个领域没有良好的业绩记录。@SteveMaughan,XE7的更新1已经发布。QC似乎已经在那里修好了。预装更新,重新编译并重新运行项目。
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;