Как стать автором
Обновить

Комментарии 12

Не совсем вижу смысла, в статье как минимум 60% времени уделяется фразе "как использовать Wait() и .Result чтобы не заблокироваться", но ведь уже давно вышла возможность использовать асинхронный Main(), и есть даже JoinableTaskFactory для критичных ситуаций вроде Windows Service Start/Stop.
Давно уже пора пометить эти Result и Wait, чтобы выдавали warning. Или еще лучше unsafe :)

Три простых совета чтобы не знать проблем с асинхронным программированием.
1) Забудьте про .Wait() и .Result как про страшный сон. Если вы программируете асинхронно они вам не нужны.
2) Забудьте про ConfigureAwait. Это костыль и мусор который захламляет код и не пригодится при выполнении пункта 1
3) Не хотите чтобы UI тормозил? прекратите работаь в потоке UI по умолчанию и вызывать асинхронные методы только когда возникает проблема. И забудьте про контексты, это мусор на который не стоит полагаться. Работайте в потоке без контекста, возвращаясь в поток UI через Dispatcher.Invoke, только тогда когда это действительно нужно.

Команда WPF сделала кучу запутанных перегрузок Dispatcher.Invoke, но вместо них сгодятся вот такие не очень красивые зато рабочие и удобные екстеншены.

public static class DispatcherExtensions
{
async public static Task InvokeAsyncTask(this Dispatcher dispatcher, Action act) =>
await dispatcher.InvokeAsync(act);

async public static Task InvokeAsyncTask(this Dispatcher dispatcher, Func act) =>
await dispatcher.InvokeAsync(act);

async public static Task InvokeAsyncTask(this Dispatcher dispatcher, Func act) =>
await await dispatcher.InvokeAsync(act);

async public static Task InvokeAsyncTask(this Dispatcher dispatcher, Func<Task> act) =>
await await dispatcher.InvokeAsync(act);
}

А можно еще вот так

public static class DispatcherObjectExtensions
{
public static Task Invoke(this DispatcherObject obj, Action act) =>
obj.Dispatcher.InvokeAsyncTask(act);

public static Task Invoke(this DispatcherObject obj, Func act) =>
obj.Dispatcher.InvokeAsyncTask(act);

public static Task Invoke(this DispatcherObject obj, Func act) =>
obj.Dispatcher.InvokeAsyncTask(act);

public static Task Invoke(this DispatcherObject obj, Func<Task> act) =>
obj.Dispatcher.InvokeAsyncTask(act);
}

неистово плюсую. все эти SyncronizationContext следует пометить как Obsolete :O

Увы, иногда интерфейс диктует синхронную реализацию, и приходится прибегать к Wait/Result. Радует, что в .Net Core эта проблема решена не приводит к блокировке

Это где она решена? По-моему в Asp.Net Core все прекрасно блокируется.

Паф! А я и не связал одно с другим. Знал, что контекста больше нет, но попрежнему считал что контекст будет заблокирован. Думал это разные контексты. Огромное спасибо за линк!
Увы, иногда интерфейс диктует синхронную реализацию

Если вы про конкретно "имплементацию" то модификатор async не влияет на сигнатуру интерфейсного метода, единственное нельзя добавить пост фикс Async, но в целом все нормально.

Не совсем. Если метод должен вернуть int, я не могу объявить функцию как async int. Исключение async void доступно только за счёт того, что возврат из метода происходит до завершения асинхронного тела функции. Так что если мне нужно дождаться завершения асинхронного метода или же получить результат, то других вариантов нет
2) Забудьте про ConfigureAwait. Это костыль и мусор который захламляет код и не пригодится при выполнении пункта 1


Ну это весьма даже опасный совет, особенно если придётся много Task-based задач выполнять параллельно — контекст будет форсировать не более 1 задачи за раз, в итоге производительность будет в разы хуже, нежели при выполнении задач на ThreadPool'е.
Ну так не отрывайте один совет от остальных) следом идет рекомендация не работать в контексте, а работать в тредпуле
Спустя полгода заметил что хабр код испортил ><
image
Зарегистрируйтесь на Хабре, чтобы оставить комментарий