Ответ 1
Я уверен, что async/await сам по себе не имеет ничего общего с concurrency/parallelism и не что иное, как реализация CPS?
Ну, async
/await
- это переписывание, использующее CPS, поэтому ваше основное понимание верное.
Что касается "concurrency" и "parallelism", я бы сказал, что он включает concurrency; вы можете запускать несколько операций async
, которые все "в полете" одновременно. Это легко сделать с Task.WhenAll
и Task.WhenAny
.
Кроме того, даже если async
сам по себе не подразумевает "многопоточность", Task.Run
позволяет легко async
-сортировать многопоточность
И реальная потоковая обработка выполняется экземпляром SynchronizationContext, который ожидает прохождения/восстановления?
Подумайте об этом так: продолжение, созданное переписыванием CPS, должно запускаться где-то. Захваченный "асинхронный контекст" можно использовать для планирования продолжения.
Боковое примечание: захваченный контекст на самом деле SynchronizationContext.Current
, если он не равен нулю, и в этом случае захваченный контекст TaskScheduler.Current
.
Еще одно важное замечание: захват и восстановление контекста фактически зависит от объекта "awaiter". Итак, по умолчанию, если вы await
a Task
(или любой другой встроенный в ожидании), контекст будет захвачен и восстановлен. Но если вы await
результат ConfigureAwait(false)
, то контекст не будет захвачен. Точно так же, если вы await
ваш собственный пользовательский ожидания, он не захватит контекст (если вы не запрограммируете его).
Однако существуют ли какие-либо гарантии, что информация контекста потока сохраняется? Я имею в виду Name, CurrentPrincipal, CurrentCulture, CurrentUICulture и т.д.
SynchronizationContext
отличается от ExecutionContext
. Упрощенный ответ заключается в том, что ExecutionContext
всегда "течет", поэтому CurrentPrincipal
потоков (если это не так, это может быть проблема безопасности, поэтому API, которые не текут ExecutionContext
, всегда заканчиваются на Unsafe
).
В приложениях пользовательского интерфейса культура не течет, но по умолчанию она одинакова для всех потоков. Name
определенно не будет течь, если вы не возобновите работу в одном потоке (например, с помощью пользовательского интерфейса SynchronizationContext
).
Для некоторого дальнейшего чтения я рекомендую начать с моего собственного async
/await
учебника, а затем официального async
/await
Часто задаваемые вопросы. Затем посмотрите сообщение в блоге Stephen Toub на ExecutionContext
и SynchronizationContext
.
Вы также можете найти мою SynchronizationContext
статью.