Предположим, у меня есть вызов для ожидания во вложенной функции в главном потоке пользовательского интерфейса.Что происходит с потоком в этой точке?Возвращается ли управление к циклу сообщений, и поток пользовательского интерфейса может свободно обрабатывать другие входные данные?
Да.Когда вы await
ожидаете (например, Task<TResult>
), текущая позиция потока в методе async
фиксируется.Затем он ставит в очередь оставшуюся часть метода («продолжение»), который должен быть выполнен, когда завершено ожидаемое (например, когда завершается Task<TResult>
).
Однако существует оптимизация, которая может иметь место:если ожидаемое уже завершено, то await
ждать не нужно, и он просто продолжает выполнение метода немедленно.Это называется «быстрый путь», описанный здесь .
Когда ожидаемая задача завершается, весь стек помещается в очередь сообщений, так что управление возвращается черезкаждая из этих вложенных функций, или здесь происходит что-то еще?
Текущая позиция потока помещается в очередь сообщений пользовательского интерфейса.Детали немного сложнее: продолжения запланированы на TaskScheduler.FromCurrentSynchronizationContext
, если SynchronizationContext.Current
не равен null
, и в этом случае они запланированы на TaskScheduler.Current
.Кроме того, это поведение может быть отменено путем вызова ConfigureAwait(false)
, который всегда планирует продолжение в пуле потоков.Поскольку SynchronizationContext.Current
является пользовательским интерфейсом SynchronizationContext
для WPF / WinForms / Silverlight, это продолжение действительно помещается в очередь сообщений пользовательского интерфейса.
И во-вторых (пока я обращаю ваше внимание), я нене понимаю, почему асинхронные методы должны быть помечены как асинхронные.Не может ли какой-либо метод выполняться асинхронно?Что если я хочу выполнить метод асинхронно, но у него нет ключевого слова async - есть ли способ сделать это просто?
Это немного разные значения слова "асинхронный".Ключевое слово async
включает ключевое слово await
.Другими словами, async
методы могут await
.Старомодные асинхронные делегаты (т. Е. BeginInvoke
/ EndInvoke
) сильно отличаются от async
.Асинхронные делегаты выполняются в потоке ThreadPool
, но методы async
выполняются в потоке пользовательского интерфейса (при условии, что они вызываются из контекста пользовательского интерфейса, а вы не вызываете ConfigureAwait(false)
).
Если вы хотитечтобы (не async
) метод выполнялся в потоке ThreadPool
, вы можете сделать это следующим образом:
await Task.Run(() => MyMethod(..));
Что я действительно хочу знать, так это то, в какой степенипродолжение продолжить ... останавливает ли он весь стек вызовов, чтобы возобновить его, когда задача завершается, или он возвращается только так далеко?Должна ли сама функция быть помечена как асинхронная для поддержки продолжения, или (как я изначально просил) она продолжает весь стек вызовов?
Текущая позиция фиксируется и «возобновляется»когда продолжение продолжается.Любая функция, которая использует await
для поддержки продолжений, должна быть помечена async
.
Если вы вызываете метод async
из не-1059 * метода, то вы должны иметь дело с Task
объект напрямую.Это обычно не делается.Методы верхнего уровня async
могут возвращать void
, поэтому нет причин не иметь обработчиков событий async
.
Обратите внимание, что async
является чисто преобразованием компилятора.Это означает, что методы async
точно так же, как обычные методы после их компиляции.Среда выполнения .NET не обрабатывает их каким-либо особым образом.