Delphi async / await emulation
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.