Как стать автором
Обновить

Async/Await из C#. Головоломка для разработчиков компилятора и для нас

Уровень сложностиСложный
Время на прочтение11 мин
Количество просмотров11K
Всего голосов 7: ↑6 и ↓1+5
Комментарии6

Комментарии 6

"Дорогой дедушка Мороз, я ничего не понял в статье Стива Тоуба. Но написал много буков, чтобы ты не сомневался, что я очень сильно старался понять.
На новый год я хочу миллион просмотров и благодарность от читателей."

Функция Impl() возвращает управление на каждом yield return, и поэтому требует многократных вызовов, как если бы она применялась из конструкции на основе foreach.

Вот с этого момента началась какая-то чушь. Нет, функция Impl() требует ровно одного вызова.

Многократные вызовы foreach делает не для функции-генератора, а для метода MoveNext. Это, вообще-то, общеизвестный факт.

Если сравнить с тем что мы имеем для «функций использующих yield return для генерации IEnumerable<> списка» по аналогии с которой мы пытаемся реализовать логику использования async функций, то окажется, что ее нельзя использовать, потому что она требует особенной конструкции с циклом для вызова по месту вызова.

Нет, yield return никогда не требовал особенной конструкции по месту вызова.

Как видите сложность анализа этого решения заключается еще и в том, что надо загрузить и держать в голове реализацию сразу нескольких взаимосвязанных классов, каждый из которых в отдельности вряд ли можно понять вне контекста логики их взаимодействия. 

Не нужно.

Пул потоков можно понять без всех остальных классов.

Задачу-Task можно понять зная лишь пул потоков.

Реализацию оператора await можно понять зная лишь Task.

Реализацию асинхронного метода можно понять зная лишь Task и реализацию await.

Реализацию оператора await можно понять зная лишь Task.

Да, понять реализацию на уровне концепции можно. Но реальная реализация там сделана сложнее. И по факту использует подход duck typing, в целом для C# нетипичный.

И это позволяет использовать кое-какие интересные трюки. У меня, например, в одном проекте есть класс, в одном из методов которого есть конструкция await this. Ревнителям чистоты кода сразу сообщу, что это - пет-проект, так что никто посторонний от такого трюка не пострадает.

Да нет, подход довольно типичный, его ещё на операторе foreach опробовали. И деконструкцией продолжили (уже после await). Да и перегрузка операторов всегда была, по сути, той же утиной.

async await нужно просто понимать как еще один способ работы с функциями возвращающими Task. реально await ждет выполнения Task. Вся "магия" с отзывчивым UI происходит на уровень выше, где-то во фреймворке, где эти Task_и честно обрабатываются по условно классической схеме. async await удобен в "нормальном" коде лишь тем, что это краткий способ запустить серию последовательных асинхронных задач и лишь "наверху" можно получить реальную асинхронность. К счастью, наверху все сделано.

После прочтения статьи у меня сложилось впечатление, что простой, но точный перевод статьи Тауба лучше бы способствовал пониманию async/await, чем данная статья. Бльно уж много в ней мыслей о том, как это всё сложно, которые IMHO только задерживают читателя.

Но, возможно, это мое впечатление обусловлено тем, что я давно знаю, как реализован async/await.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации