Delphi async / await emulation
C # introduced the async / await construct. The following is an example of how to achieve this behavior on Delphi.
I assume you are familiar with async / await. It is convenient to use for operations where processor involvement is not required. The processor is just starting the operation, and from the outside world comes to report its end. A good example is a call to a web server. Let's say our web server can perform two operations: addition and multiplication.
The client wants to evaluate the expression (1 + 2) * (3 + 4). Because the results of the additions are independent, they can be performed simultaneously:
Before the line "// 3" (the first await), the method executes in the usual way. On await, the method exits, and continues (until the next await) at the end of the operation. Control will be transferred by the message mechanism or in another thread - it is configured in the environment. In C #, this is achieved by the compiler. In Delphi, similar behavior on a single thread can be achieved with Fiber. A similar method would look like:
The example works for Delphi 2007, XE2, XE8.
I assume you are familiar with async / await. It is convenient to use for operations where processor involvement is not required. The processor is just starting the operation, and from the outside world comes to report its end. A good example is a call to a web server. Let's say our web server can perform two operations: addition and multiplication.
async Task MakeAsyncTask_Plus(int aArg1, int aArg2, int aDurationMs)
{ // эмуляция вызова на веб сервер
await Task.Delay(aDurationMs);
return aArg1 + aArg2;
}
async Task MakeAsyncTask_Mult(int aArg1, int aArg2, int aDurationMs)
{ // эмуляция вызова на веб сервер
await Task.Delay(aDurationMs);
return aArg1 * aArg2;
}
The client wants to evaluate the expression (1 + 2) * (3 + 4). Because the results of the additions are independent, they can be performed simultaneously:
async void CalcAsync()
{
Task aPlus1 = MakeAsyncTask_Plus(1, 2, 2000); // 1
Task aPlus2 = MakeAsyncTask_Plus(3, 4, 2000); // 2
int aArg1 = await aPlus1; // 3
int aArg2 = await aPlus2; // 4
Task aMult = MakeAsyncTask_Mult(aArg1, aArg2, 1000); // 5
int aRes = await aMult; // 6
Log(string.Format("{0} * {1} = {2}", aArg1, aArg2, aRes));
}
Before the line "// 3" (the first await), the method executes in the usual way. On await, the method exits, and continues (until the next await) at the end of the operation. Control will be transferred by the message mechanism or in another thread - it is configured in the environment. In C #, this is achieved by the compiler. In Delphi, similar behavior on a single thread can be achieved with Fiber. A similar method would look like:
procedure TCalcAsync.Execute;
var
aPlus1: TAsyncTask;
aPlus2: TAsyncTask;
aMult: TAsyncTask;
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.