Comments 17
Странный у вас C# код:)
Расскажите поподробнее про возврат в текущий поток и как передается управление. Как это внутри сделано? Используется IOCP?
async Task CalcAsync()
{
var aArg1 = await AddAsync(1, 2, 2000);
var aArg2 = await AddAsync(3, 4, 2000);
var aRes = MultiplyAsync(aArg1, aArg2, 1000);
Log($"{aArg1} * {aArg2} = {aRes}");
}
Расскажите поподробнее про возврат в текущий поток и как передается управление. Как это внутри сделано? Используется IOCP?
-4
Код на C# как раз нормальный. А вот на Delphi не сделано ровным счетом ничего. Визуально похоже, но работает совершенно не так.
+3
Видимо кого-то задело, что это все в 4 строки пишется, но код и в самом деле выглядит притянутым за уши для аналогии с Delphi. И как раз был вопрос про то как это работает.
0
Так ведь весь прикол в том, что оно не работает. В C# между await'ами UI поток свободен и может выполнять другие задачи, а код Delphi вынес обработку в другой поток, но UI поток занят.
0
Ну дак я и спрашиваю автора дальше об этом:
Все это выглядит как Task.Result, но были упомянуты какие-то сообщения..
Управление передастся механизмом сообщений или в другом потоке — настраивается в окружении
Все это выглядит как Task.Result, но были упомянуты какие-то сообщения..
0
Все это выглядит как Task.Result, но были упомянуты какие-то сообщения..
Ну вообще,
SynchronizationContext.Post
— это вполне себе сообщение, а именно так работает постановка continuation на определенный контекст (по умолчанию в await
это включено).+1
1) Покажите, пожалуйста, строчку кода, которая выполняется не в главном потоке.
2) Откуда информация, что главный поток занят? Что вам мешает повторно нажать на кнопочку "Async" во время "вычислений"?
Добавил логирование сообщения на выход из обработчика нажатия:
procedure TExample.btStartAsyncClick(Sender: TObject);
begin
// mmLog.Clear;
TCalcAsync.Create.Switch;
Log('btStartAsyncClick finish', []);
end;
Дважды быстро нажал на "Async". Получил лог (обратите внимание на положение этого сообщения — оно между сообщениями из TCalcAsync.Execute):
1 + 2 start
3 + 4 start
btStartAsyncClick finish
1 + 2 start
3 + 4 start
btStartAsyncClick finish
1 + 2 = 3
3 + 4 = 7
3 7 start
1 + 2 = 3
3 + 4 = 7
3 7 start
3 7 = 21
3 7 = 21
2) Откуда информация, что главный поток занят? Что вам мешает повторно нажать на кнопочку "Async" во время "вычислений"?
Добавил логирование сообщения на выход из обработчика нажатия:
procedure TExample.btStartAsyncClick(Sender: TObject);
begin
// mmLog.Clear;
TCalcAsync.Create.Switch;
Log('btStartAsyncClick finish', []);
end;
Дважды быстро нажал на "Async". Получил лог (обратите внимание на положение этого сообщения — оно между сообщениями из TCalcAsync.Execute):
1 + 2 start
3 + 4 start
btStartAsyncClick finish
1 + 2 start
3 + 4 start
btStartAsyncClick finish
1 + 2 = 3
3 + 4 = 7
3 7 start
1 + 2 = 3
3 + 4 = 7
3 7 start
3 7 = 21
3 7 = 21
+2
Оператор await работает следующим образом:
Реально там все еще сложнее — главным образом, из-за необходимости повторно выбрасывать исключения с сохранением стектрейса.
Большую часть реализации можно увидеть начиная отсюда: http://referencesource.microsoft.com/#mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs,108
Также реализация await упрощенна расписана в комментарии к файлу http://referencesource.microsoft.com/#mscorlib/system/runtime/compilerservices/TaskAwaiter.cs
Магия шагов 1 и 8 (возобновление метода) реализуется компилятором.
- Проверяет, не выполнена ли уже задача. Если выполнена — то у нее просто извлекается значение (или исключение) и больше ничего не делается.
- Захватывает текущий контекст синхронизации или планировщик задач.
- У задачи вызывается метод ContinueWith, в который передается лямбда, указывающая на шаг 5.
- Управление из метода возвращается.
- (Вызывается асинхронно после выполнения задачи) Если на шаге 2 был захвачен контекст синхронизации — то шаг 8 алгоритма вызывается в нем асинхронно при помощи метода Post
- Если на шаге 2 баз захвачен планировщик задач — то шаг 8 алгоритма запускается в нем как задача
- если на шаге 2 ничего захвачено не было — то шаг 8 выполняется сразу же
- Продолжается выполнение метода, начиная с текущего оператора await (т.е. с шага 1).
Реально там все еще сложнее — главным образом, из-за необходимости повторно выбрасывать исключения с сохранением стектрейса.
Большую часть реализации можно увидеть начиная отсюда: http://referencesource.microsoft.com/#mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs,108
Также реализация await упрощенна расписана в комментарии к файлу http://referencesource.microsoft.com/#mscorlib/system/runtime/compilerservices/TaskAwaiter.cs
Магия шагов 1 и 8 (возобновление метода) реализуется компилятором.
0
Sign up to leave a comment.
Эмуляция async/await в Delphi