📜 ⬆️ ⬇️

Async / await emulation in Delphi

In C #, the async / await construction appeared. The following is an example of how to achieve this behavior in Delphi.

I assume that you are familiar with async / await. It is convenient to use it for operations where the participation of the processor is not required. The processor is just starting the operation, and from the outside world comes a message about its termination. A good example is a call to a web server. Suppose our web server is able to perform two operations: addition and multiplication.
async Task<int> MakeAsyncTask_Plus(int aArg1, int aArg2, int aDurationMs) { //      await Task.Delay(aDurationMs); return aArg1 + aArg2; } async Task<int> MakeAsyncTask_Mult(int aArg1, int aArg2, int aDurationMs) { //      await Task.Delay(aDurationMs); return aArg1 * aArg2; } 

The client wants to calculate the expression (1 + 2) * (3 + 4). Since results of additions are independent, they can be performed simultaneously:
  async void CalcAsync() { Task<int> aPlus1 = MakeAsyncTask_Plus(1, 2, 2000); // 1 Task<int> aPlus2 = MakeAsyncTask_Plus(3, 4, 2000); // 2 int aArg1 = await aPlus1; // 3 int aArg2 = await aPlus2; // 4 Task<int> aMult = MakeAsyncTask_Mult(aArg1, aArg2, 1000); // 5 int aRes = await aMult; // 6 Log(string.Format("{0} * {1} = {2}", aArg1, aArg2, aRes)); } 

Before the string "// 3" (the first await) method works in the usual way. The await method exits the method, and continues (until the next await) at the end of the operation. The control will be transferred by the message engine or in another thread - it is configured in the environment. In C #, this is achieved by the compiler features. In Delphi, similar behavior on a single thread can be achieved using Fiber. This method will look like:
 procedure TCalcAsync.Execute; var aPlus1: TAsyncTask<Integer>; aPlus2: TAsyncTask<Integer>; aMult: TAsyncTask<Integer>; aArg1, aArg2: Integer; aRes: Integer; begin aPlus1 := nil; aPlus2 := nil; aMult := nil; try aPlus1 := TAsyncTask_Plus.Create(Self, 1,{+}2, 2000{ms}); aPlus2 := TAsyncTask_Plus.Create(Self, 3,{+}4, 2000{ms}); aArg1 := aPlus1.Await; aArg2 := aPlus2.Await; aMult := TAsyncTask_Mult.Create(Self, aArg1,{*}aArg2, 1000{ms}); aRes := aMult.Await; Example.Log('%d * %d = %d', [aArg1, aArg2, aRes]); finally aMult.Free; aPlus2.Free; aPlus1.Free; end; end; 

The example works for Delphi 2007, XE2, XE8.

')

Source: https://habr.com/ru/post/278985/


All Articles