Delphi D10.X 并行库PPL编程之 TParallel.For

news/2024/12/20 13:35:17/

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方面其他技术支持、定制开发。

现在就进店看看

以上信息对您有用的话请点赞收藏,就下面这行


http://www.ppmy.cn/news/934202.html

相关文章

Delphi D10.X安卓开发中按两次返回键退出系统的方法

在安卓APP应用中&#xff0c;通常按下返回键后会关闭程序&#xff0c;有时候我们为了避免误按返回健导致程序的退出&#xff0c;会对按下返回健进行检测&#xff0c;并要求连续按下两次才退出程序。 在Delphi中开发安卓时&#xff0c;如何检测并实现两次退出APP呢。你可以使用发…

Delphi D10.X中实现安卓中文语音合成(中文朗读)就这么简单

前言 语音合成&#xff0c;据说Android系统从1.6版本开始就支持TTS&#xff08;Text-To-Speech&#xff09;。但是android系统默认的TTS引擎:Pic TTS不支持中文。好在现在国内较多的手机都已安装好中文的TTS引擎。使用Delphi开发一个可以朗读中文的APP就非常的简单。 本文给大…

Spring D10

天地不仁&#xff0c;以万物为刍狗 文章目录 前言一、Transactional二、Spring的两种事务处理方式2.1注解式的事务2.2声明式事务&#xff08;必须掌握&#xff09; 三、为什么添加事务管理器四、Spring事务的传播特性总结 前言 Transactional(propagation Propagation.REQUIR…

【拿来就能用】C#用于打印机打印的类

之前写过一个“C#WinForm程序中选择打印机打印”的文章&#xff0c;但在使用过程中&#xff0c;尤其是生成Word文档时&#xff0c;会感觉系统响应较慢。如果不需要留存打印文档的电子版&#xff0c;可以使用下面的类直接打印。相比之前的方法&#xff0c;这种方法更简单&#x…

Delphi D10.X 并行库PPL编程之 Futures

Delphi D10.X 并行库PPL编程系列之 Futures delphi中的RTL&#xff08;运行库&#xff09;提供了并行编程库&#xff08;PPL --Parallel Programming Library&#xff09; &#xff0c;让您的应用程序可以在跨平台应用中有效的使用多个CPU并行运行任务的能力。 Futures 让流程…

D10总结

目录 1.迭代器与生成器的区别 2.Python常见的异常 3.匿名函数 4.type和isinstance的区别 5.__new__魔法方法 6.__iter__魔法方法 7.SQLito 8.MySQL 9.内存地址 10.生成式 11.四个阶段构成计算机的电子元器 12.字节转换 13.with open 14.Linux中常用压缩格式 15Py…

Delphi D10.1 移动开发中APP界面基本布局(一)

Delphi 目前在移动应用开发上已越来越成熟&#xff0c;其高效、简洁的开发更让人喜欢。 #说明 案例演示使用Delphi控件完成界面基本布局&#xff0c;其中包括TLayout、TVertScrollBox、 TGridPanelLayout、TTabControl 等控件的基本使用。 本案例仅使用Delphi自身控件实现&am…

随想录D10 | 232,225

232.用栈实现队列 使用栈实现队列的下列操作&#xff1a; push(x) -- 将一个元素放入队列的尾部。 pop() -- 从队列首部移除元素。 peek() -- 返回队列首部的元素。 empty() -- 返回队列是否为空。 示例: MyQueue queue new MyQueue(); queue.push(1); queue.push(2)…