Delphi D10.X 并行库PPL编程系列之 TParallel.For
delphi中的RTL(运行库)提供了并行编程库(PPL --Parallel Programming Library) ,让您的应用程序可以在跨平台应用中有效的使用多个CPU并行运行任务的能力。
使用TParallel.For 使循环更快。
TParallel.For说明
TParallel.For通过指定的整数索引值进行迭代,对每次迭代都调用事件处理程序,在并行线程中执行这些调用的程序。迭代器事件是否在并行线程中处理取决于可用的线程资源和性能。
为了表示他与常规的For是一样的功能,TParallel.For同样也使用了For的名称,但TParallel.For使用的是并行执行方式,而不象常规for循环一样一个接一个地串行执行。
TParallel.For重载方法
为了适应不同的需要,TParallel.For提供了很多的重载方法,虽然每个TParallel.For重载方法本质上执行相同的操作,但每个重载方法因参数不同,在执行期间提供功能与信息也是不同的。
以下是不同的重载方法:
class function &For(Sender: TObject; ALowInclusive, AHighInclusive: Integer; AIteratorEvent: TIteratorEvent): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; ALowInclusive, AHighInclusive: Integer; AIteratorEvent: TIteratorEvent; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; ALowInclusive, AHighInclusive: Integer; AIteratorEvent: TIteratorStateEvent): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; ALowInclusive, AHighInclusive: Integer; AIteratorEvent: TIteratorStateEvent; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; AStride, ALowInclusive, AHighInclusive: Integer; AIteratorEvent: TIteratorEvent): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; AStride, ALowInclusive, AHighInclusive: Integer; AIteratorEvent: TIteratorEvent; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; AStride, ALowInclusive, AHighInclusive: Integer; AIteratorEvent: TIteratorStateEvent): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; AStride, ALowInclusive, AHighInclusive: Integer; AIteratorEvent: TIteratorStateEvent; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(ALowInclusive, AHighInclusive: Integer; const AIteratorEvent: TProc<Integer>): TLoopResult; overload; static; inline;
class function &For(ALowInclusive, AHighInclusive: Integer; const AIteratorEvent: TProc<Integer>; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(ALowInclusive, AHighInclusive: Integer; const AIteratorEvent: TProc<Integer, TLoopState>): TLoopResult; overload; static; inline;
class function &For(ALowInclusive, AHighInclusive: Integer; const AIteratorEvent: TProc<Integer, TLoopState>; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(AStride, ALowInclusive, AHighInclusive: Integer; const AIteratorEvent: TProc<Integer>): TLoopResult; overload; static; inline;
class function &For(AStride, ALowInclusive, AHighInclusive: Integer; const AIteratorEvent: TProc<Integer>; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(AStride, ALowInclusive, AHighInclusive: Integer; const AIteratorEvent: TProc<Integer, TLoopState>): TLoopResult; overload; static; inline;
class function &For(AStride, ALowInclusive, AHighInclusive: Integer; const AIteratorEvent: TProc<Integer, TLoopState>; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; ALowInclusive, AHighInclusive: Int64; AIteratorEvent: TIteratorEvent64): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; ALowInclusive, AHighInclusive: Int64; AIteratorEvent: TIteratorEvent64; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; ALowInclusive, AHighInclusive: Int64; AIteratorEvent: TIteratorStateEvent64): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; ALowInclusive, AHighInclusive: Int64; AIteratorEvent: TIteratorStateEvent64; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; AStride, ALowInclusive, AHighInclusive: Int64; AIteratorEvent: TIteratorEvent64): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; AStride, ALowInclusive, AHighInclusive: Int64; AIteratorEvent: TIteratorEvent64; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; AStride, ALowInclusive, AHighInclusive: Int64; AIteratorEvent: TIteratorStateEvent64): TLoopResult; overload; static; inline;
class function &For(Sender: TObject; AStride, ALowInclusive, AHighInclusive: Int64; AIteratorEvent: TIteratorStateEvent64; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(ALowInclusive, AHighInclusive: Int64; const AIteratorEvent: TProc<Int64>): TLoopResult; overload; static; inline;
class function &For(ALowInclusive, AHighInclusive: Int64; const AIteratorEvent: TProc<Int64>; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(ALowInclusive, AHighInclusive: Int64; const AIteratorEvent: TProc<Int64, TLoopState>): TLoopResult; overload; static; inline;
class function &For(ALowInclusive, AHighInclusive: Int64; const AIteratorEvent: TProc<Int64, TLoopState>; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(AStride, ALowInclusive, AHighInclusive: Int64; const AIteratorEvent: TProc<Int64>): TLoopResult; overload; static; inline;
class function &For(AStride, ALowInclusive, AHighInclusive: Int64; const AIteratorEvent: TProc<Int64>; APool: TThreadPool): TLoopResult; overload; static; inline;
class function &For(AStride, ALowInclusive, AHighInclusive: Int64; const AIteratorEvent: TProc<Int64, TLoopState>): TLoopResult; overload; static; inline;
class function &For(AStride, ALowInclusive, AHighInclusive: Int64; const AIteratorEvent: TProc<Int64, TLoopState>; APool: TThreadPool): TLoopResult; overload; static; inline;
可以看到,TParallel.For的所有重载都会返回TParallel.TLoopResult。在执行完TParallel.For iterator事件的所有迭代后,TParallel.For返回的TLoopResult中,会将 Completed 设置为True。
TLoopResult 定义如下:
TLoopResult = recordprivateFCompleted: Boolean;FLowestBreakIteration: Variant;publicproperty Completed: Boolean read FCompleted;property LowestBreakIteration: Variant read FLowestBreakIteration;end;
在使用具有Sender参数的TParallel.For重载时,需要调用者传递一个对象实例,这个对象实例将在每次迭代中作为其Sender参数发送给迭代事件,这与RAD Studio中的其他事件处理程序一样。对于不需要Sender参数参与到事件过程中的,可以将Sender设置为nil传递给迭代事件。
TParallel.For的所有重载方法都涉及参数ALowInclusive和AHighInclusive,它们是Integer或Int64值,分别表示迭代的上下边界。也就是说,如果ALowInclusive的值设置为1、AHighInclusive设置为4,则迭代器事件将在1和4之间执行。
AStride参数允许您调整并行运行的性能。TParallel.For循环使用线程池来管理与执行工作。如果需要执行的工作很少,使用过多的线程反而可能会影响其最终性能。如果将AStride参数设置为大于1,然后根据AStride为每项工作进行分组。这减少这个数值,会减少同步开销上的时间,但代价是减少了循环中的并行性。
迭代事件处理程序的区别在于迭代范围Integer或Int64的大小,以及是否存在TParallel.TLoopState,可以参看下面涉及Sender参数方法的类型定义。
TIteratorEvent = procedure (Sender: TObject; AIndex: Integer) of object;TIteratorStateEvent = procedure (Sender: TObject; AIndex: Integer; const LoopState: TLoopState) of object;TIteratorEvent64 = procedure (Sender: TObject; AIndex: Int64) of object;TIteratorStateEvent64 = procedure (Sender: TObject; AIndex: Int64; const LoopState: TLoopState) of object;
不是所有迭代事件处理程序都有Sender参数,你也可以使用不带Sender参数的方法,只是他们并没定义为类型。例如:
const AIteratorEvent: TProc<Int64>
当APool参数指定TThreadPool时,可以通过TThreadPool.SetMinWorkerThreads和ThreadPool.SetMaxWorkerThreads方法来控制迭代事件可用的线程资源。
在使用这些方法时,过多的并发线程会产生开销,从而会减少或消除并行执行程序的优势。
TParallel.For演示
演示中使用到的控件
使用两个按钮分别执行常规For循环及TParallel.For,通过Memo显示执行结果。
添加使用单元
usesSystem.Threading, // 需要引用PPL库System.Diagnostics,System.SyncObjs;
先建立一个计算函数
//演示用的执行计算的函数
function IsPrime(N: Integer): Boolean;
varTest, k: Integer;
beginif N <= 3 thenIsPrime := N > 1else if ((N mod 2) = 0) or ((N mod 3) = 0) thenIsPrime := FalseelsebeginIsPrime := True;k := Trunc(Sqrt(N));Test := 5;while Test <= k dobeginif ((N mod Test) = 0) or ((N mod (Test + 2)) = 0) thenbeginIsPrime := False;break; { 跳出for循环 }end;Test := Test + 6;end;end;
end;
设置一个常数
constMax =5000000;
分别为两个按钮增加处理事件
procedure TForm5.Button2Click(Sender: TObject);
varI, Tot: Integer;SW: TStopwatch;
begin// 计算低于给定值的质数Tot:=0;SW := TStopWatch.Create;SW.Start;for I := 1 to Max dobeginif IsPrime(I) thenInc(Tot);end;SW.Stop;Memo1.Lines.Add(Format('顺序For循环。 时间(以毫秒为单位):%d - 找到质数:%d', [SW.ElapsedMilliseconds,Tot]));
end;procedure TForm5.Button3Click(Sender: TObject);
varTot: Integer;SW: TStopwatch;
begintry// 计算低于给定值的质数Tot :=0;SW :=TStopWatch.Create;SW.Start;TParallel.For(2,1,Max,procedure(I:Int64)beginif IsPrime(I) thenTInterlocked.Increment(Tot);end);SW.Stop;Memo1.Lines.Add(Format('并行循环。 时间(以毫秒为单位):%d - 找到质数:%d', [SW.ElapsedMilliseconds,Tot]));except on E:EAggregateException doShowMessage(E.ToString);end;
end;
演示效果
使用并行循环明显提高了程序的运行效率。
具体使用请参阅
使用并行编程库
并行库PPL编程之 TTask
并行库PPL编程之 Futures
演示Demo
可下载本系列文章对应的演示程序,含代码。使用D10.3.2编辑。
Delphi D10.X 使用并行编程库使用演示
欢迎光顾本人小店:(https://shop63778938.taobao.com/)
小店也提供delphi方面其他技术支持、定制开发。
现在就进店看看
以上信息对您有用的话请点赞收藏,就下面这行