В C# появилась конструкция async/await. Далее показан вариант как добиться подобного поведения на Delphi.
Я предпологаю, что вы знакомы с async/await. Её удобно использовать для операций, где участие процессора не требуется. Процессор только начинает операцию, а из внешнего мира приходит сообщают об её окончании. Хорошим примером может служить вызов на веб сервер. Допустим наш веб сервер умеет выполнять две операции: сложение и умножение.
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; }
Клиент хочет вычислить выражение (1+2)*(3+4). Т.к. результаты сложений независимы, их можно выполнять одновременно:
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)); }
До строки "//3"(первого await) метод отрабатывает обычным образом. На await происходит выход из метода, а продолжится (до следующего await) по окончанию операции. Управление передастся механизмом сообщений или в другом потоке — настраивается в окружении. В C# это достигается возможностями компилятора. В Delphi похожего поведения на одном потоке можно достичь при помощи Fiber. Выглядеть подобный метод будет похоже:
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;
Пример работает для Delphi 2007, XE2, XE8.
ссылка на оригинал статьи https://habrahabr.ru/post/278985/
Добавить комментарий