.NET Разработчик
6.55K subscribers
442 photos
3 videos
14 files
2.12K links
Дневник сертифицированного .NET разработчика. Заметки, советы, новости из мира .NET и C#.

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День триста двадцать первый. #AsyncAwaitFAQ
FAQ по async/await и ConfigureAwait
Async/await были добавлены в .NET более 7 лет назад. За это время было выпущено множество улучшений в инфраструктуре, дополнительных языковых конструкций, API-интерфейсов. Однако один из аспектов async/await, который продолжает вызывать вопросы, - это ConfigureAwait. В серии постов #AsyncAwaitFAQ мы ответим на несколько наиболее часто задаваемых вопросов про контекст синхронизации в async/await.
1. Что такое контекст синхронизации?
Документация по System.Threading.SynchronizationContext утверждает, что он «обеспечивает базовую функциональность для распространения контекста синхронизации в различных моделях синхронизации». Не совсем понятное описание.
В 99,9% случаев SynchronizationContext - это тип, который предоставляет виртуальный метод Post, принимающий делегат для асинхронного выполнения (в SynchronizationContext есть множество других виртуальных членов, но они гораздо реже используются). Метод Post базового типа просто вызывает ThreadPool.QueueUserWorkItem для асинхронного вызова предоставленного делегата. Однако производные типы переопределяют метод Post, чтобы разрешить выполнение этого делегата в наиболее подходящем месте и в наиболее подходящее время.
В Windows Forms переопределённый метод Post, создаёт эквивалент Control.BeginInvoke. То есть любые вызовы метода Post приведут к тому, что делегат будет вызван позже в потоке, связанном с этим элементом управления, т.е. в UI-потоке. Windows Forms полагается на обработку сообщений Win32 и имеет «цикл сообщений», работающий в UI-потоке, который просто ожидает поступления новых сообщений для обработки (движения и щелчки мыши, ввод с клавиатур, системные события, делегаты и т. д.). Таким образом, имея экземпляр SynchronizationContext для UI-потока приложения Windows Forms, чтобы получить делегат для выполнения в UI-потоке, просто нужно передать его в Post.
WPF имеет свой собственный производный от SynchronizationContext тип с переопределённым Post, который аналогично «маршализирует» делегат в UI-поток (через Dispatcher.BeginInvoke), в данном случае управляемый диспетчером WPF, а не элементом управления Windows Forms.
В Windows RunTime (WinRT) переопределённый метод Post, также ставит делегат в очередь UI-потока через CoreDispatcher.
Это выходит за рамки простого «запуска этого делегата в UI-потоке». Любой может реализовать SynchronizationContext с методом Post, который делает всё что угодно.
Преимуществом такого подхода в том, что он предоставляет единый API, который можно использовать для постановки в очередь делегата для обработки, как того пожелает создатель реализации, без необходимости знать детали этой реализации. Итак, если я пишу библиотеку, и я хочу асинхронно выполнить некоторую работу, а затем поставить делегат в очередь обратно в «контекст» исходного местоположения, мне просто нужно захватить SynchronizationContext, сохранить его, а затем, когда я закончу свою работу, вызвать Post в этом контексте и передать делегат, который я хочу вызвать. Мне не нужно знать, что для Windows Forms я должен взять Control и использовать его BeginInvoke, или для WPF я должен взять Dispatcher и использовать его BeginInvoke, и т.п. Мне просто нужно взять текущий SynchronizationContext и использовать его позже. Чтобы достичь этого, SynchronizationContext предоставляет свойство Current, так что для достижения вышеупомянутой цели можно написать такой код:
public void DoWork(Action worker, Action completion)
{
SynchronizationContext sc = SynchronizationContext.Current;
ThreadPool.QueueUserWorkItem(_ =>
{
try { worker(); }
finally { sc.Post(_ => completion(), null); }
});
}
Платформа, которая хочет предоставить свой контекст в свойстве Current, использует метод SynchronizationContext.SetSynchronizationContext.

Источник: https://devblogs.microsoft.com/dotnet/configureawait-faq/
👍1