使用Omni Thread Library在Delphi中异步获取函数结果 [英] Get a function result asynchronously in Delphi using Omni Thread Library

查看:80
本文介绍了使用Omni Thread Library在Delphi中异步获取函数结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从另一个单元/类中调用一个函数,这将花费一些时间来执行该任务并返回一个字符串值.我找不到很好的参考,类似于Delphi中的C#async-await之类的简单方法.对我来说,使用Omni Thread库似乎是个好主意.

I am trying to call a function from another unit/class which would take some time in performing the task and would return a string value. I couldn't find a good reference something similar to C# async-await like simple approach in Delphi. Using Omni Thread library seems a good idea for me.

一个简单的例子对我来说是一个很好的开始.

A simple example will be a great start for me.

示例方法:

procedure TForm1.button1Click(Sender: TObject);
begin
  // notify before starting the task
  memo1.Lines.Add('calling a asynchronous function..');

  // call to the function that takes some time and returns a string value
  memo1.Lines.Add(GetMagicString);

  // notify that the task has been completed
  memo1.Lines.Add('Results fetched successfully.');
end;

在这里,函数 GetMagicString 应该异步处理结果.获得结果后,程序才应通知任务已完成.顺便说一下,我正在使用Delphi-XE.

Here, the function GetMagicString should process the result asynchronously. Once the result is obtained, only then the program should notify that the task has been completed. By the way, I'm using Delphi-XE.

这是我尝试过的.但是我仍然无法找出完成工作的正确方法.问题是如何返回值.

Here is what I tried. But I am still unable to figure out the proper way to make the job done. The problem is how to return the value.

  .....
    private
      ResultValue: IOmniFuture<string>;
    .........
    .....


    function TForm1.FutureGet: string;
    begin
      Sleep(3000);
      Result := 'my sample magic string response ' +  IntToStr(Random(9999));
    end;

    procedure TForm1.FutureGetTerminated;
    begin
      // This code fired when the task is completed
      memo1.Lines.Add(ResultValue.Value);
    end;

    function TForm1.GetMagicString: string;
    begin
      ResultValue := Parallel.Future<string>(FutureGet,
            Parallel.TaskConfig.OnTerminated(FutureGetTerminated));

    end;

在这里,使用Result:= ResultValue.Value使UI变得柔和.

Here, using Result := ResultValue.Value feezes the UI.

Edit2

我根据提供的答案进行了更改.

I made changes as per the answer provided.

MainForm代码: 单位Unit1;

MainForm Code: unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Unit2;



type
  TForm1 = class(TForm)
    memo1: TMemo;
    button1: TButton;
    procedure button1Click(Sender: TObject);
  private
    FOnStringReceived: TMyEvent;
    procedure StringReceived(const AValue: string);
    property OnStringReceived: TMyEvent read FOnStringReceived write FOnStringReceived;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


procedure TForm1.button1Click(Sender: TObject);
var
  MyObject: TMyClass;
begin
  // notify before starting the task
  memo1.Lines.Add('calling a asynchronous function..');

  // call to the function that takes some time and returns a string value
  MyObject := TMyClass.Create;
  OnStringReceived := StringReceived;
  try
    MyObject.GetMagicStringInBackground(OnStringReceived);
  finally
    MyObject.Free;
  end;
end;


procedure TForm1.StringReceived(const AValue: string);
begin
  memo1.Lines.Add(AValue);

   // notify that the task has been completed
  memo1.Lines.Add('Results fetched successfully.');
end;
end.

其他单位代码: 单位Unit2;

Other Unit Code: unit Unit2;

interface

uses SysUtils, OtlTask, OtlParallel, OtlTaskControl;

type
  TMyEvent = procedure(const aValue: string) of object;

type
  TMyClass = class
  private
    FOnStringReceived: TMyEvent;
    function GetMagicString: string;
  public
    procedure GetMagicStringInBackground(AEvent: TMyEvent);
end;

implementation

{ TMyClass }

function TMyClass.GetMagicString: string;
begin
  Sleep(3000);
  Result := 'my sample magic string response ' +  IntToStr(Random(9999));
end;

procedure TMyClass.GetMagicStringInBackground(AEvent: TMyEvent);
var
  theFunctionResult: string;
begin
  Parallel.Async(
    procedure
    begin
      theFunctionResult := GetMagicString;
    end,

    Parallel.TaskConfig.OnTerminated(
    procedure (const task: IOmniTaskControl)
    begin
      if Assigned(AEvent) then
        AEvent(theFunctionResult);
    end)
  );
end;
end.

是的,代码按预期工作.我只想知道这是否是我真正想要执行的最佳方法.

Yes, the code works as expected. I just want to know if this is the best way of doing what I really want to perform.

推荐答案

通常情况下,如果希望在后台执行某些操作但仍需要在相同的执行路径中执行结果,则通常使用Future.基本上,它使您可以在后台执行某些操作,同时在主线程中执行另一操作,然后可以使用后台线程的结果.

You would normally use a future in a case where you want something executed in the background but still need the result in the same execution path. It basically lets you do something in the background while doing another thing in the main thread and you can then use the result of the background thread.

您需要使用的是TLama链接到的异步抽象:

What you need to use is the Async abstraction that TLama linked to:

在您的情况下,它将是:

In your case it would be:

procedure TForm1.DoSomething;
var
  theFunctionResult: string;
begin
  memo1.Lines.Add('calling a asynchronous function..');
  Parallel.Async(
    procedure
    begin
      // executed in background thread
      theFunctionResult := GetMagicString;
    end,

    procedure
    begin
      // executed in main thread after the async has finished
      memo1.Lines.Add(theFunctionResult);

      // notify that the task has been completed
      memo1.Lines.Add('Results fetched successfully.');
    end
  );
end;

这有点混乱,但是您应该明白这一点.在破坏拥有该代码的表单(TForm1)之前,您需要确保异步代码已完成.

This is a bit messy but you should get the idea. You need to make sure that your async code is completed before you destroy the form that owns this code (TForm1).

如果您想尝试建立一个在代码完成时将调用事件的系统,则可以执行以下操作:

If you want to try and setup a system that will call an event when the code completes then you can do something like this:

type
  TMyEvent = procedure(const aValue: string) of object;

procedure GetMagicStringInBackground(AEvent: TMyEvent);
var
  theFunctionResult: string;
begin
  Parallel.Async(
    procedure
    begin
      // executed in background thread
      theFunctionResult := GetMagicString;
    end,

    Parallel.TaskConfig.OnTerminated(
      procedure (const task: IOmniTaskControl)
      begin
        // executed in main thread after the async has finished
        if Assigned(AEvent) then
          AEvent(theFunctionResult );
      end
    )
  );
end;

然后,您可以将线程代码放入GetMagicString单元中,并从表单中调用上面的方法,并传递一个事件,该事件将在完成时被调用.

You can then put the threaded code in the GetMagicString unit and just call the method above from your form passing in an event that will get called when it completes.

这篇关于使用Omni Thread Library在Delphi中异步获取函数结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆