SynchronizationContext
- это более старый API, предназначенный для обеспечения координации нескольких потоков друг с другом. В частности, это исторически происходит из мира пользовательского интерфейса, такого как winforms, где есть основной поток пользовательского интерфейса, и если у вас есть фоновая работа, может потребоваться вернуть обратно в поток пользовательского интерфейса, чтобы выполнять операции, такие как обновления пользовательского интерфейса. Для этого существует несколько механизмов, и SynchronizationContext
является одним из них. По сути, это предоставляет два API: Post
и Send
(главное отличие состоит в том, что Send
блокирует ожидание завершения работы).
Теперь, совершенно отдельно от этого, async
/ await
- это другая модель API для выполнения асинхронного кода, т. Е.
var foo = await BarAsync();`
SomethingElse(foo);
Здесь, если BarAsync
завершается синхронно, код просто продолжает нормально работать и SomethingElse
выполняется немедленно; но если BarAsync
возвращает неполное - то есть асинхронно - тогда поток раскручивается , возвращая управление туда, откуда он пришел, и продолжение подключается так, что будет запускать SomethingElse
, когда станет доступен результат из BarAsync
.
Если эти две модели пересекаются, это означает, что реализация await
знает о существовании SynchronizationContext
и , если он существует , он (по умолчанию) будет захватывать syn c -контекст, существовавший в то время, и возобновлять выполнение через этот syn c -context (Post
) при основание того, что вы , вероятно, хотите вернуться в эту модель многопоточности, а не в модель потока того, что вызвало завершение BarAsync
. Это поведение можно настроить (отключить) с помощью ConfigureAwait
:
var foo = await BarAsync().ConfigureAwait(false);`
SomethingElse(foo);
Теперь оно будет , а не захватывать syn c -контекст, и когда незавершенная операция возобновляется, никаких дополнительных косвенность будет вызываться. Это полезно для избежания дополнительного переключения контекста, но означает, что некоторые вещи (например, обновление пользовательского интерфейса) могут потерпеть неудачу. Обычно (но не универсально) код приложения редко использует ConfigureAwait
, а библиотека обычно использует ConfigureAwait
.