我试图在Delphi中异步运行一个函数或过程,但是没有使用组件,有没有办法用delphi核心函数来做呢?
答案 0 :(得分:17)
如果你问VCL是否有开箱即用的like BeginInvoke in .NET,那么答案是否定的。但是,您可以通过Andreas Hausladen的AsyncCalls库链接到您的程序的小单元形式获得非常相似的内容。它不是一个组件,所以我猜它有资格。它还支持从版本5开始的Delphi。非常推荐。
修改强>
我会添加一个例子,因为你没有让它运行。如果你的调用代码被阻塞,那么你的问题是没有引用该函数返回的IAsyncCall
接口指针。因此,当临时引用超出范围时,将立即销毁实现该接口的对象。析构函数将在VCL线程的上下文中调用,它将调用WaitForSingleObject()
或类似的函数来等待工作线程完成。结果是你的VCL线程阻塞。
如果您保持对接口指针的引用,您将获得正确的行为:
type
TForm1 = class(TForm)
Button1: TButton;
Timer1: TTimer;
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure Button1Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
fAsyncCall: IAsyncCall;
procedure WaitForIt(ADelay: integer);
end;
将计时器设置为禁用,并使其具有非常短的Interval
,例如50 ms。按钮单击启动异步操作:
procedure TForm1.Button1Click(Sender: TObject);
begin
Button1.Enabled := FALSE;
fAsyncCall := AsyncCall(WaitForIt, 1000);
end;
procedure TForm1.WaitForIt(ADelay: integer);
begin
Sleep(ADelay);
EnterMainThread;
try
Randomize;
Color := RGB(Random(256), Random(256), Random(256));
Timer1.Enabled := TRUE;
finally
LeaveMainThread;
end;
end;
当操作处于活动状态时,无法启动其他操作。完成后,它使计时器能够通知表单并重置接口引用:
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := FALSE;
Assert((fAsyncCall <> nil) and fAsyncCall.Finished);
fAsyncCall := nil;
Button1.Enabled := TRUE;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := (fAsyncCall = nil) or fAsyncCall.Finished;
end;
请注意,甚至可以使用EnterMainThread()
和LeaveMainThread()
直接从被调用的方法访问表单。
以上代码不是绝对最低限度,只是为了展示一些想法。
答案 1 :(得分:5)
您可能还想在线程上执行您的过程。然后使用OnTerminate事件来获取结果。是的,在.NET和C#的这些日子里,我们对异步执行方法的简单方便形式有所不满,但这就是它在Delphi上运行的方式。