退出TParallel.For循环的最快方法?

时间:2017-05-04 18:28:55

标签: multithreading delphi delphi-10.1-berlin

当用户单击“取消”按钮或用户关闭/销毁表单时,我需要以最快的方式退出TParallel.For循环。我已尝试使用TParallel.TLoopState.StopTParallel.TLoopState.Break

var
  BreakCondition: Boolean;

procedure TForm2.DoStartLoop;
begin
  BreakCondition := False;
  System.Threading.TParallel.For(1, 50,
    procedure(idx: Integer; LS: TParallel.TLoopState)
    begin
      if BreakCondition then
      begin
        //LS.&BREAK;
        LS.STOP;
        //EXIT;
      end
      else
        DoProcessValue(idx);
    end);
end;

不幸的是,TParallel.TLoopState.StopTParallel.TLoopState.Break的Embarcadero文档仅指出:

  

Embarcadero Technologies目前没有任何额外的补充   信息。

我还认为循环不会很快中断。还有更好的方法吗?

1 个答案:

答案 0 :(得分:2)

From the TParallel.For documentation

  

如果迭代器事件需要控制迭代本身,则迭代器事件处理程序应该是使用TParallel.TLoopState参数的处理程序。如果存在,将为事件处理程序提供TParallel.TLoopState的实例,可以从中监视来自FaultedStoppedShouldExit的状态信息,或者迭代循环本身可以使用BreakStop方法进行控制。

跟踪LoopState的方法是使用具有以下签名的方法:

TIteratorStateEvent = 
  procedure (Sender: TObject; AIndex: Integer; const LoopState: TLoopState) of object;

或使用其匿名版本:

class function &For(AStride, ALowInclusive, AHighInclusive: Integer; 
const AIteratorEvent: TProc<Integer, TLoopState>; APool: TThreadPool): TLoopResult;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

如果文档失败,最简单的方法是搜索类的源代码,或者让代码完成工作。

TLoopState = class
    private [...]
    public
      procedure Break;
      procedure Stop;
      function ShouldExit: Boolean;  <<-- this looks useful

      property Faulted: Boolean read GetFaulted;
      property Stopped: Boolean read GetStopped;  <<-- or this
      property LowestBreakIteration: Variant read GetLowestBreakIteration;
    end;

示例:

procedure TForm1.btnParallelForClick(Sender: TObject);
var
  Tot: Integer;
  SW: TStopwatch;
begin
     try
     // counts the prime numbers below a given value
       Tot :=0;
       SW :=TStopWatch.Create;
       SW.Start;
       //Use a method that supports LoopState
       TParallel.For(2,1,Max,procedure(I:Int64; State: TLoopState)
       begin
         //check loopstate every now and again.
         if State.ShouldExit then exit;  
         if IsPrime(I) then TInterlocked.Increment(Tot);
       end);
     SW.Stop;
      Memo1.Lines.Add(Format('Parallel For loop. Time (in milliseconds): %d - Primes found: %d', [SW.ElapsedMilliseconds,Tot]));
     except on E:EAggregateException do
      ShowMessage(E.ToString);
     end;
end;