Подтвердить что ты не робот

Является ли мое понимание асинхронным/ожидающим, как это работает и его преимущества, правильно?

Я несколько раз утверждал свое понимание async/await, часто с некоторыми дебатами относительно того, насколько я прав. Я был бы очень признателен, если бы кто-нибудь мог подтвердить или опровергнуть мое понимание и прояснить любые заблуждения, чтобы я не распространял дезинформацию.

Высокоуровневое понимание

async/await - это способ избежать обратного вызова ада при написании асинхронного кода. Нить, выполняющая асинхронный метод, вернется в пул потоков, когда встретится с await, и выполнит выполнение после завершения ожидаемой операции.

Низкоуровневое понимание

JIT разделит асинхронные методы на отдельные части вокруг точек await, что позволит повторно войти в метод с сохранением состояния метода. Под обложками подразумевается какая-то государственная машина.

Отношение к Concurrency

async/await не подразумевает какой-либо concurrency. Приложение, написанное с использованием async/await, может быть полностью однопоточным, при этом все еще пожиная все преимущества, так же как и node.js, хотя и с обратными вызовами. В отличие от node.js,.NET многопоточен, поэтому, имея async/await, вы получаете преимущества неблокирующего ввода-вывода без использования обратных вызовов, а также с несколькими потоками выполнения.

Преимущества

async/await освобождает потоки, чтобы делать другие вещи, ожидая завершения ввода-вывода. Его также можно использовать в сочетании с TPL для работы с ЦП, связанной с несколькими потоками, или от потока пользовательского интерфейса.

Чтобы извлечь выгоду из неблокирующего IO, асинхронные методы должны быть построены поверх API, которые фактически используют неблокирующий IO, которые в конечном итоге предоставляются ОС.

Неправильное использование

Это самая большая точка зрения в моем понимании. Многие считают, что перенос операции блокировки в Task и использование async/await приведет к увеличению производительности. Создав дополнительный поток для обработки операции, возвращая исходный поток в пул потоков, а затем возобновляя исходный метод после завершения задачи, все, что происходит, являются ненужными переключателями контекста, хотя и не освобождает потоки для выполнения другой работы. Хотя это не столько злоупотребление async/await, сколько и TPL, это мышление, похоже, связано с непониманием async/await.

4b9b3361

Ответ 1

Это очень правильно.

Несколько заметок:

  • Нить, которая начинает выполнение асинхронного метода, является потоком вызывающего, который может или не может быть потоком ThreadPool.
  • Если ожидание достигнуто, но ожидаемый (обычно Task) уже завершен, поток продолжит выполнение остальной части метода синхронно.
  • Нить, которая возобновляет запуск метода, обычно представляет собой поток ThreadPool, но это зависит от SyncrhonizationContext и TaskScheduler.
  • JIT здесь не участвует (не чаще обычного). Компилятор - это тот, который превращает асинхронный метод в конечный автомат. Вы можете видеть, что с этот пример TryRoslyn.
  • Это правда, что async-await не обязательно подразумевает concurrency, поскольку он может быть однопоточным. Тем не менее, он может быть одновременно одновременно с одним потоком, одновременно запуская и ожидая нескольких асинхронных операций.
  • async-wait и TPL не являются полностью отдельными частями. async-await построен поверх TPL. Именно поэтому он назвал Асинхронный шаблон на основе задач.
  • Хотя наиболее асинхронными операциями являются операции ввода-вывода, не все они. Вы также обычно задерживаете асинхронно с Task.Delay или используете асинхронные конструкции синхронизации, такие как SemaphoreSlim.WaitAsync.