异步编程,是项目中非常有用的而且常用的一种方法,大多以线程实现。
而Delphi传统方法使用线程略为烦琐,好在其后续版本中,提供一些方法,简化一些操作。
几个概念:
匿名线程:TAnonymousThread,Delphi XE始支持。
匿名方法:reference to procedure|function,Delphi 2009 始支持。
匿名线程
其实只是创建一个线程,传入一匿名方法并执行,实现倒也简单,我就移其入Dephi 2009中。其实义如下:
TAnonymousThread = class(TThread) private FProc: TProc; protected procedure Execute; override; public constructor Create(const AProc: TProc); end;
{ TAnonymousThread } constructor TAnonymousThread.Create(const AProc: TProc); begin inherited Create(True); FreeOnTerminate := True; FProc := AProc; end; procedure TAnonymousThread.Execute; begin FProc(); end;
这样,使用简单的多线程,就不必再继承TThread类创建自己线程去工作了。其参数TProc,即为一匿名方法。
而在TThread类中,定义一类方法直接创建,其方法为:
// CreateAnonymousThread will create an instance of an internally derived TThread that simply will call the // anonymous method of type TProc. This thread is created as suspended, so you should call the Start method // to make the thread run. The thread is also marked as FreeOnTerminate, so you should not touch the returned // instance after calling Start as it could have run and is then freed before another external calls or // operations on the instance are attempted. class function CreateAnonymousThread(const ThreadProc: TProc): TThread; static;
class function TThread.CreateAnonymousThread(const ThreadProc: TProc): TThread; begin Result := TAnonymousThread.Create(ThreadProc); end;
由此可见,一行代码即可实现简单的线程操作。
匿名方法
自定义匿名方法,正式语法为:
type TFun = reference to function(const num: Integer): Integer;
procedure也是一样。但在SysUtils单元中,已内置一些预定义类型并且支持泛型,可直接拿来用,如下所示:
// Generic Anonymous method declarations type TProc = reference to procedure; TProc<T> = reference to procedure (Arg1: T); TProc<T1,T2> = reference to procedure (Arg1: T1; Arg2: T2); TProc<T1,T2,T3> = reference to procedure (Arg1: T1; Arg2: T2; Arg3: T3); TProc<T1,T2,T3,T4> = reference to procedure (Arg1: T1; Arg2: T2; Arg3: T3; Arg4: T4); TFunc<TResult> = reference to function: TResult; TFunc<T,TResult> = reference to function (Arg1: T): TResult; TFunc<T1,T2,TResult> = reference to function (Arg1: T1; Arg2: T2): TResult; TFunc<T1,T2,T3,TResult> = reference to function (Arg1: T1; Arg2: T2; Arg3: T3): TResult; TFunc<T1,T2,T3,T4,TResult> = reference to function (Arg1: T1; Arg2: T2; Arg3: T3; Arg4: T4): TResult; TPredicate<T> = reference to function (Arg1: T): Boolean;
我是喜欢懒省事的,有已有的即不再自写,上面诸多类型,已能应对大多数使用场景了。
需要注意的是TFunc使用方法,因为它有返回值。比如TFunc<Integer, Interger>就与TFun实现原理一样。
可验证如下代码:
procedure TfrmMain.FormCreate(Sender: TObject); var f1: TFun; f2: TFunc<Integer, string>; begin f1 := function (const num: Integer): Integer begin Result := num * num; end; OutputDebugString(PChar('f1(9) = ' + IntToStr(f1(9)))); //Debug output: f1(9) = 81 f2 := function (num: Integer): string begin Result := IntToStr(num * num); end; OutputDebugString(PChar('f2(9) = ' + f2(9))); //Debug output: f2(9) = 81 end;
由此可延伸开来,匿名线程与匿名方法结合,可简单的执行并行操作,举例如下:
procedure TfrmMain.btnStartClick(Sender: TObject); begin Edit1.Text := 'start...'; TThread.CreateAnonymousThread( procedure var i: Integer; begin Sleep(3000); for i := 0 to 99999 do TThread.Synchronize(nil, procedure begin Edit1.Text := IntToStr(i); end ); Edit1.Text := 'end.'; //此处亦要同步,懒省事没整Synchornize end ).Start; end;
创建一匿名线程,传以匿名方法,并同步主线程显示,工作正常。相比c#之{}来说,begin..end的确看起业不像话。
多省事,是不是?
参考资料: