170 похожих чатов

Вопрос: вызов await блокирует поток? Я понимаю, что такой код:


var result = await DoWorkAsync();
Console.WriteLine(result);
разворачивается компиляторов в

var awaiter = DoWorkAsync();
awaiter.OnCompleted(() =>
var result1 = awaiter.GetResult();
Console.WriteLine(result);
)
Получается допустим работают два потока: основной и поток из тредпула
Основной доходит до вызова функции, заходит в DoWorkAsync(), и почти моментально оттуда выходит и может дальше работать.
На этом этапе DoWorkAsync() начинает исполнять поток из тредпула.
Основной поток ожидает признак продолжения, для того, чтобы выполнить операторы дальше.

Вот тут не понятно: основной поток ждет - означает ли это то, что он заблокирован? Или там под капотом как-то хитро устроено, что поток живой, но просто курит, пока поток из пула не скажет, мол я закончил работу - продолжай

4 ответов

25 просмотров

Все треды свободны, если у тебя по-настоящему асинхронная работа с IO, а не только вычисления. https://blog.stephencleary.com/2013/11/there-is-no-thread.html

Mikhail-Izmailov Автор вопроса
Ilya L
Все треды свободны, если у тебя по-настоящему асин...

Я читаю вот его книгу как раз Что означает асинхронная IO ? Подключение к базе данных это IO. Как я понимаю, асинхронность в этом случае заключается в том, что поток, который инициирует подключение - возвращается в тредпул на то время, пока БД не подключится, если не применять ConfigureAwait(false);

Для начала нужно понять, что такое стейт машина. Самая простая стейт машина это IEnumerator<T> Это просто метод MoveNext() и свойство Current. Теперь самое интересное - пишем цикл foreach, который работает с этим интерфейсом под капотом. Для пользователя это интерфейс IEnumerable<T>, но он сразу возвращает IEnumerator<T>, и дальше работа идет только с этим интерфейсом. Посмотрите этот интерфейс, и попробуйте понять, что именно компилятор делает. Посмотрите il, который генерится. Попробуйте реализовать свой IEnumerator<T> с помощью yield return, а потом попробуйте написать ручками тот же самый код. Получится, что вам прийдется сохранить состояние, и использовать в методе MoveNext() оператор switch case, который будет это состояние использовать. То есть код foreach метода на самом деле разбивается на куски, которые вызываются по отдельности в рамках отдельных клауз switch case, в зависимости от состояния. С async/await происходит подобная история - async await это всего лишь синтаксический сахар к стейт машине. То есть, не просто генерится код, который тут же выходит - вызывающий метод это тоже стейтмашина. И кто-то должен вызывать метод MoveNext() много раз подряд. В промежутках между этими вызовами никакого потока нет. Этот “кто-то”, который вызывает ваш код снова и снова происходит во взятом из тредпула треде. По сути можно считать, что это каждый раз новый тред, хотя это на самом деле просто спящие треды переиспользуются из тредпула. А пробуждает этот тред прерывание, которое зарегистрировано в каком-либо драйвере. То есть, в промежутке нет никакого потока.

George Polevoy
Для начала нужно понять, что такое стейт машина. ...

То есть, ваш пример кода валидный, но он не вполне объясняет, что происходит. Следует понимать, что он находится в рамках клаузы case внутри switch, и за один вход в метод MoveNext выполняется только одна клауза, потом следует return. ``` MoveNext() { switch (this._state) { case START: var awaiter = DoWorkAsync(); this._state = WORK_STARTED; break; case WORK_STARTED: var result1 = awaiter.GetResult(); Console.WriteLine(result); break; } } ```

Похожие вопросы

Обсуждают сегодня

30500 за редактор? )
Владимир
47
а через ESC-код ?
Alexey Kulakov
29
Чёт не понял, я ж правильной функцией воспользовался чтобы вывести отладочную информацию? но что-то она не ловится
notme
18
У меня есть функция где происходит это: write_bit(buffer, 1); write_bit(buffer, 0); write_bit(buffer, 1); write_bit(buffer, 1); write_bit(buffer, 1); w...
~
14
Недавно Google Project Zero нашёл багу в SQLite с помощью LLM, о чём достаточно было шумно в определённых интернетах, которые сопровождались рассказами, что скоро всех "ибешни...
Alex Sherbakov
5
Ребят в СИ можно реализовать ООП?
Николай
33
Как передать управляющий символ в открытую через CreateProcess консоль? Собсна, есть процедура: procedure TRedirectThread.WriteData(Data: OEMString); var Written: Cardinal;...
Serjone
6
в JclConsole объявлено так: function CtrlHandler(CtrlType: DWORD): BOOL; stdcall; - где ваше объявление с stdcall? у вас на картинке нет stdcall
Karagy
8
https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_h_common.erl#L174 https://github.com/erlang/otp/blob/OTP-27.1/lib/kernel/src/logger_olp.erl#L76 15 лет назад...
Maksim Lapshin
20
~ 2m21s  nix shell github:nixos/nixpkgs#stack ~  stack ghc -- --version error: … while calling the 'derivationStrict' builtin at /builtin/derivation.nix:...
Rebuild your mind.
6
Карта сайта