【转】Delphi XE7并行编程:TTask.IFuture
(2016-07-08 13:16:44)分类: Delphi10.1 |
原文地址,以下为全文,在此向作者致敬。
在前一节中,我讲述了TTask及如何快速开发可并行执行多任务的应用程序。接下来,我们准备探究构建在ITask基础上的IFuture。
IFuture 允许通过泛型的定义,来创建一个可以返回指定类型值的任务。使用IFuture的实例,计算过程可以并行执行,然后我们可先继续做其他事,直到需要用到它 的返回值为止。这样,我们便可以按自己所希望的顺序来编写代码块,但仍然能确保在需要返回值的时候获取到它。
要从Future里取得一个值,你首先需要定义它返回的类型,然后去调用。下面演示一下它的使用:
procedure TFormThreading.Button3Click(Sender: TObject);
var
OneValue:
IFuture<integer> ;
OtherValue: Integer;
Total: Integer;
begin
OneValue :=
TTask.Future<integer>(
function: Integer
begin
Result :=
ComputeSomething;
Sleep(1000); // delay to show
status
end);
Memo1.Lines.Add(TRttiEnumerationType.
GetName(OneValue.Status));
OtherValue
:= ComputeSomething;
Memo1.Lines.Add(TRttiEnumerationType.
GetName(OneValue.Status));
Total := OtherValue +
OneValue.Value;
Memo1.Lines.Add(TRttiEnumerationType.
GetName(OneValue.Status));
// result
Memo1.Lines.Add(Total.ToString);
end;
以上代码的运行结果类似这样:
WaitingToRun
Running
Completed
1333400
第一步,是使用TTask.Future定义返回值的类型,然后传递一个返回同样类型的匿名函数给它。
调用TTask.Future的结果是一个IFuture的实例,我们把它保存到了OneValue变量里。
好吧,放Sleep命令在匿名函数里确实很没意义,但它将允许我们在运行代码的时候,能看到OneValue.Status的各种状态变化。
OneValue := TTask.Future(function: Integer
begin
Result :=
ComputeSomething;
Sleep(1000); // delay to show
status
end);
继续往下看,你会看到我们查询了OneValue的当前状态。这段代码把Future的状态转换成一个字符串。
TRttiEnumerationType.GetName(OneValue.Status)
第一个状态值是WaitingToRun,表示一切已准备就绪。
紧接着,我们调用了同样的ComputeSomething任务,它在当前线程中执行
OtherValue := ComputeSomething;
然后,我们再次检查OneValue的状态,这次显示是Running
等等!这是否意味着我们在取得返回值时,需要一直检查它的状态?当然不需要^_^
Total := OtherValue + OneValue.Value;
这一行向OneValue请求了它的返回值。如果它已经执行完成,会直接获取到返回值;如果还没有,则会阻塞等待IFuture执行完成。这减少了我们开发者的许多工作。
后记:
在Delphi 10.1 berlin下,正常运行,要引用System.RTTI.Pas单元.:
procedure TForm18.Button1Click(Sender: TObject);
var
OneValue: IFuture<integer>;
OtherValue: Integer;
Total: Integer;
begin
OneValue := TTask.Future<integer>(
function:
Integer
begin
Result := 1000;
Sleep(1000); // delay to show status
end);
//单步跟踪,上面这行是立即执行完成,并执行下一行.也就是说,这一行开启一个线程来执行对应的匿名函数,计算OneValue。
Memo1.Lines.Add(TRttiEnumerationType.GetName(OneValue.Status));
OtherValue := 1000;
Memo1.Lines.Add(TRttiEnumerationType.GetName(OneValue.Status));
Total := OtherValue +
OneValue.Value;//这一行,才真正等OneValue对应的线程实现完毕.如果线程执行时间长,这一步会卡死界面,实际代码中要考虑。
Memo1.Lines.Add(TRttiEnumerationType.GetName(OneValue.Status));
// result
Memo1.Lines.Add(Total.ToString);
end;
总结来说,要使用TTask.IFuture,分三步:
1.声明一个IFuture的泛型接口变量,如:
FutureString:IFuture<string>
FutureInteger:IFuture<integer>
2.在代码中利用TTask.IFuture发启计算这一变量的线程,开始计算这一变量,如:
FutureString:=TTask.Future<string>(
Function:string
begin
...
result:='返回的string';
end);
FutureInteger:=TTask.Future<Integer>(
function:Integer
begin
...
result:=1000;//返回整型结果.
end);
3.在实际代码中引用FutureXXX变量的值,通过IFuture.Value取得,如:
s:=FutureString.Value;
i:=FutureInteger.Value;
确实强大,简化了并发编程。
在前一节中,我讲述了TTask及如何快速开发可并行执行多任务的应用程序。接下来,我们准备探究构建在ITask基础上的IFuture。
IFuture 允许通过泛型的定义,来创建一个可以返回指定类型值的任务。使用IFuture的实例,计算过程可以并行执行,然后我们可先继续做其他事,直到需要用到它 的返回值为止。这样,我们便可以按自己所希望的顺序来编写代码块,但仍然能确保在需要返回值的时候获取到它。
要从Future里取得一个值,你首先需要定义它返回的类型,然后去调用。下面演示一下它的使用:
procedure TFormThreading.Button3Click(Sender: TObject);
var
begin
end;
以上代码的运行结果类似这样:
第一步,是使用TTask.Future定义返回值的类型,然后传递一个返回同样类型的匿名函数给它。
调用TTask.Future的结果是一个IFuture的实例,我们把它保存到了OneValue变量里。
好吧,放Sleep命令在匿名函数里确实很没意义,但它将允许我们在运行代码的时候,能看到OneValue.Status的各种状态变化。
OneValue := TTask.Future(function: Integer
begin
end);
继续往下看,你会看到我们查询了OneValue的当前状态。这段代码把Future的状态转换成一个字符串。
TRttiEnumerationType.GetName(OneValue.Status)
第一个状态值是WaitingToRun,表示一切已准备就绪。
紧接着,我们调用了同样的ComputeSomething任务,它在当前线程中执行
OtherValue := ComputeSomething;
然后,我们再次检查OneValue的状态,这次显示是Running
等等!这是否意味着我们在取得返回值时,需要一直检查它的状态?当然不需要^_^
Total := OtherValue + OneValue.Value;
这一行向OneValue请求了它的返回值。如果它已经执行完成,会直接获取到返回值;如果还没有,则会阻塞等待IFuture执行完成。这减少了我们开发者的许多工作。
后记:
在Delphi 10.1 berlin下,正常运行,要引用System.RTTI.Pas单元.:
procedure TForm18.Button1Click(Sender: TObject);
var
begin
end;
总结来说,要使用TTask.IFuture,分三步:
1.声明一个IFuture的泛型接口变量,如:
FutureString:IFuture<string>
FutureInteger:IFuture<integer>
2.在代码中利用TTask.IFuture发启计算这一变量的线程,开始计算这一变量,如:
FutureString:=TTask.Future<string>(
FutureInteger:=TTask.Future<Integer>(
3.在实际代码中引用FutureXXX变量的值,通过IFuture.Value取得,如:
s:=FutureString.Value;
i:=FutureInteger.Value;
确实强大,简化了并发编程。