Из того, что я понимаю, Await ключевое слово будет приостановить поток кода, пока функция не возвращает
Ну, да и №
- Да, потому что поток кода в каком-то смысле останавливается.
- Нет, потому что поток, выполняющий этот поток кода, не блокируется. (Синхронный вызов
client.GetString()
заблокирует поток).
Фактически, он вернется к своему методу вызова. Чтобы понять, что это значит, вернувшись к его вызывающему методу, вы можете прочитать о другом мастере компилятора C# - в заявлении yield return
.
итераторы блоки с yield return
сломаются метод в состоянии машины - где код после yield return
заявления будет выполнять только после того, как MoveNext()
вызывается счетчику. (См. this и this).
Теперь, async/await
механизм также основан на аналогичной машине состояния (однако, ее гораздо сложнее, чем yield return
автомат).
Для упрощения, давайте рассмотрим простой метод асинхронной:
public async Task MyMethodAsync()
{
// code block 1 - code before await
// await stateement
var r = await SomeAwaitableMethodAsync();
// code block 2 - code after await
}
- Когда вы отмечаете метод с
async
идентификатором компилятору разбить метод в государственную машину, и что вы собираетесь await
внутри этот способ.
- Скажем, код работает по потоку
Thread1
, и ваш код называет это MyMethodAsync()
. Затем code block 1
будет синхронно работать в одном потоке.
SomeAwaitableMethodAsync()
также будет вызываться синхронно, но позволяет сказать, что метод запускает новую асинхронную операцию и возвращает Task
.
- Это когда
await
вступает в картину. Он вернет поток кода обратно к вызывающему абоненту, и поток Thread1
может свободно запускать код вызывающих абонентов. То, что происходит тогда в методе вызова, зависит от того, является ли метод вызова await
s на MyMethodAsync()
или делает что-то еще - но важная вещь Thread1
не заблокирована.
- Теперь остальное волшебство ожидания - Когда Задача, возвращаемая
SomeAwaitableMethodAsync()
, заканчивается, code block 2
является Запланировано для запуска.
async/await
построен на параллельной библиотеке задач - так, это Планирование выполнено по TPL.
- Теперь дело в том, что этот
code block 2
не может быть запланирован на ту же тему: Thread1
, если только он не был активным SynchronizationContext
с привязкой к потоку (например, WPF/WinForms UI thread). await
- SynchronizationContext
известно, поэтому code block 2
назначается на тот же SynchronizationContext
, если есть, когда был вызван MyMethodAsync()
. Если не было активных SynchronizationContext
, то при всей возможности code block 2
будет работать над несколькими потоками.
Наконец, я скажу, что с async/await
основана на государственной машине, созданной компилятором, как yield return
, он разделяет некоторые недостатки - например, вы не можете await
Внутри finally
блока.
Надеюсь, это прояснит ваши сомнения.
Он не блокирует основной контекст выполнения/поток, так, например, Пользовательский интерфейс не будет заморожен (в приложении, использующем интерфейс). –
Но это в основном потому, что сам метод является 'async', правильно? Разве это не означает, что до тех пор, пока он занят вещами, вызывающий поток может продолжаться? – Rijk
Нет, требуется асинхронный вызов, чтобы он мог вызвать ожидание. Вся магия происходит в ожидании. – ghord