QWorker更新-增加对For循环并行计算支持

QWorker新增了和XE7的System.Threading单元的For循环并发支持,方法是TQForJobs.For(xxx)。XE7中的For循环在等待作业完成前,如果在主线程中阻塞消息循环处理,这样子,会造成界面的假死。QWorker的For循环解决了这一问题,AMsgWait参数设置为True时,如果当前等待处于主线程中时,会使用消息循环等待;如果不处于主线程,则死等。同时QWorker的For语法支持2007-XE7的所有版本的Delphi,而不仅仅局限于XE7。

先看下QWorkerk中For的函数语法:

class function TQForJobs.&For(const AStartIndex, AStopIndex: NativeInt;
  AWorkerProc: TQForJobProc; AMsgWait: Boolean; AData: Pointer;
  AFreeType: TQJobDataFreeType): TWaitResult;
class function TQForJobs.&For(const AStartIndex, AStopIndex: NativeInt;
  AWorkerProc: TQForJobProcA; AMsgWait: Boolean; AData: Pointer;
  AFreeType: TQJobDataFreeType): TWaitResult;
class function TQForJobs.&For(const AStartIndex, AStopIndex: NativeInt;
  AWorkerProc: TQForJobProcG; AMsgWait: Boolean; AData: Pointer;
  AFreeType: TQJobDataFreeType): TWaitResult;

【参数说明】

AStartIndex:循环起始值

AStopIndex:循环结束值

AWorkerProc:作业处理过程,有三种重载,分别对应类成员函数、匿名函数和全局函数版本。

AMsgWait:是否在等待时允许消息循环,如果为True,则主线程不会被阻塞,消息能够正常处理,程序自己处理必要的阻塞,否则,主线程被阻塞。

AData:作业附加数据,被当做作业的Data成员传递给作业处理函数。

AFreeType:作业附加数据类型,用于决定是否自动释放作业的附加数据,默认由用户负责释放。

【返回值】

返回循环结果,如果成功从AStartIndex循环到AStopIndex,则返回wrSignaled,如果被中途取消(调用Break,或者程序退出),则返回wrAbandoned。

【注意】

AStopIndex应该大于等于AStartIndex,否则循环过程将不会被执行。不象普通的for语句有downto来逆序,TQForJobs.For函数不支持逆序。

【备注】

我们看下For作业过程与普通的作业过程的不同:

TQForJobProc = procedure(ALoopMgr: TQForJobs; AJob: PQJob; AIndex: NativeInt) of object;
TQForJobProcG = procedure(ALoopMgr: TQForJobs; AJob: PQJob;AIndex: NativeInt);
TQForJobProcA = reference to procedure(ALoopMgr: TQForJobs; AJob: PQJob;AIndex: NativeInt);

与普通的作业过程相比,For循环作业过程多了两个参数:

(1)、ALoopMgr参数是循环作业的控制对象,它提供了一个BreakIt方法用于中断循环的执行;

(2)、AIndex参数指明了当前循环的索引值,表明它是第几个循环。

至于AJob参数,其含义与普通的作业没有任何区别。

【示例】

下面的例子是匿名函数版本:

var
  ARuns:NativeInt;
  T,T1:Cardinal;
  I: Integer;
begin
ARuns:=0;
T:=GetTickCount;
TQForJobs.For(0,999999,
  procedure (AMgr: TQForJobs; AJob: PQJob; AIndex: NativeInt)
  begin
  AtomicIncrement(ARuns);
  end
  ,False,nil);
T:=GetTickCount-T;
ShowMessage(IntToStr(T)+'ms');
end;

下面的例子是类成员函数版本:

procedure TForm1.DoForJobProc(AMgr: TQForJobs; AJob: PQJob; AIndex: NativeInt);
begin
InterlockedIncrement(PInteger(AJob.Data)^);
end;

procedure TForm1.Button1Click(Sender:TObject);
var
  ARuns:NativeInt;
  T,T1:Cardinal;
  I: Integer;
begin
ARuns:=0;
T:=GetTickCount;
TQForJobs.For(0,999999,DoForJobProc,False,@ARuns);
T:=GetTickCount-T;
ShowMessage(IntToStr(T)+'ms');
end;

全局函数版本与类成员函数版本一致,只是作业过程变成全局函数而已,就不啰嗦了。

分享到: