Pull to refresh

Comments 17

Странный у вас C# код:)

        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?
Код на C# как раз нормальный. А вот на Delphi не сделано ровным счетом ничего. Визуально похоже, но работает совершенно не так.
Видимо кого-то задело, что это все в 4 строки пишется, но код и в самом деле выглядит притянутым за уши для аналогии с Delphi. И как раз был вопрос про то как это работает.
Так ведь весь прикол в том, что оно не работает. В C# между await'ами UI поток свободен и может выполнять другие задачи, а код Delphi вынес обработку в другой поток, но UI поток занят.
Ну дак я и спрашиваю автора дальше об этом:

Управление передастся механизмом сообщений или в другом потоке — настраивается в окружении

Все это выглядит как Task.Result, но были упомянуты какие-то сообщения..
Все это выглядит как Task.Result, но были упомянуты какие-то сообщения..

Ну вообще, SynchronizationContext.Post — это вполне себе сообщение, а именно так работает постановка continuation на определенный контекст (по умолчанию в await это включено).
Ну и хотелось бы узнать как точно то работает на Delphi :)
Из вашего коммента не очевидно, к какому коду был вопрос. Судя по количеству ответов — не мне одному.
"Расскажите поподробнее про возврат в текущий поток и как передается управление. Как это внутри сделано? Используется IOCP?"
… и все это под C#-ным кодом. Вот вам и рассказывают про C#-ный код.
Я просто отформатировал код автора, что бы не пугало людей, которые с C# не сильно знакомы :) Извиняюсь ели ввел в заблуждение.
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
Извиняюсь. Не туда посмотрел. Действительно, UI не занят.

Но все равно так писать — извражение.
Покажите, пожалуйста, строчку кода, которая выполняется не в главном потоке.

Вы про свой код или про C#?
Оператор await работает следующим образом:

  1. Проверяет, не выполнена ли уже задача. Если выполнена — то у нее просто извлекается значение (или исключение) и больше ничего не делается.
  2. Захватывает текущий контекст синхронизации или планировщик задач.
  3. У задачи вызывается метод ContinueWith, в который передается лямбда, указывающая на шаг 5.
  4. Управление из метода возвращается.

  5. (Вызывается асинхронно после выполнения задачи) Если на шаге 2 был захвачен контекст синхронизации — то шаг 8 алгоритма вызывается в нем асинхронно при помощи метода Post
  6. Если на шаге 2 баз захвачен планировщик задач — то шаг 8 алгоритма запускается в нем как задача
  7. если на шаге 2 ничего захвачено не было — то шаг 8 выполняется сразу же

  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 (возобновление метода) реализуется компилятором.
Зачем вы мне про C# И .Net? Это я и так знаю. Вопрос был к автору — как именно это реализовано на Delphi.
Никак. Это не реализовано.
Sign up to leave a comment.

Articles