Синхронизация Async/await — серебряная пуля на любой случай? ⇐ C#
Синхронизация Async/await — серебряная пуля на любой случай?
Я думаю, что это одна из самых ужасных тем в async/await, возможно, только для C#, поскольку другие языки, похоже, не имеют таких ужасных ограничений. Об этой конкретной проблеме и о том, как с ней предположительно бороться, написано множество вопросов и блогов. Спустя много лет я до сих пор не знаю, как к этому подойти...
Проблема
С чем мы сталкиваемся довольно часто, так это с реализацией наших моделей представлений. Там у нас есть типичный RelayCommand, а с помощью сообщества Mvvm мы даже получаем AsyncRelayCommand. Ни один из них не позволяет использовать метод async CanExecute. Конструкторам этих типов требуется Func для аргумента canExecute.
В некоторых случаях нам необходимо вызвать асинхронный код из canExecute следующим образом
UpdateCommand = новый AsyncRelayCommand(Update, SomeCanExecuteMethod); ... ... частный bool SomeCanExecuteMethod() { вернуть _someDependency.DoSomethingAsync().Result; } Вопрос Теперь предположим, что мы сделали все так, как предполагалось при реализации DoSomethingAsync, и каждый вызов await правильно настроен с помощью ConfigureAwait(false). Может ли приведенная выше конструкция привести к тупику?
Альтернативный вариант
Предполагая, что ответ на вышеприведенный вопрос положительный, будет ли это всегда предотвращать потенциальную тупиковую ситуацию?
private bool SomeCanExecuteMethod() { вернуть Task.Run(async () => { return await _someDependency.DoSomethingAsync().ConfigureAwait(false); }).Результат; } Честно говоря, я не могу объяснить, почему это может решить проблему. Я кое-что помню (смутно), что это имеет своего рода побочный эффект: устанавливает для контекста синхронизации значение null, что, в свою очередь, предотвращает возникновение тупиковой ситуации.
Второй вариант
Поскольку альтернативный вариант (если он верен) немного напоминает «программирование с побочными эффектами», не лучше ли было бы указать явно и явно установить нулевой контекст синхронизации?
частный bool SomeCanExecuteMethod() { вар контекст = SynchronizationContext.Current; SynchronizationContext.SetSynchronizationContext(null); результат вар = _someDependency.DoSomethingAsync().Result; SynchronizationContext.SetSynchronizationContext(контекст); вернуть результат; }
ПРИМЕЧАНИЕ. Со смешением асинхронного и синхронного кода мы сталкиваемся чаще, чем только в этом примере MVVM. Нам также приходится иметь дело с наследием, которое в некоторых случаях просто слишком агрессивно, чтобы полностью выполнить рефакторинг для асинхронного ожидания. Поэтому мы ищем «серебряную пулю» для решения проблемы смешивания асинхронного и синхронного кода, если таковая имеется...
Я думаю, что это одна из самых ужасных тем в async/await, возможно, только для C#, поскольку другие языки, похоже, не имеют таких ужасных ограничений. Об этой конкретной проблеме и о том, как с ней предположительно бороться, написано множество вопросов и блогов. Спустя много лет я до сих пор не знаю, как к этому подойти...
Проблема
С чем мы сталкиваемся довольно часто, так это с реализацией наших моделей представлений. Там у нас есть типичный RelayCommand, а с помощью сообщества Mvvm мы даже получаем AsyncRelayCommand. Ни один из них не позволяет использовать метод async CanExecute. Конструкторам этих типов требуется Func для аргумента canExecute.
В некоторых случаях нам необходимо вызвать асинхронный код из canExecute следующим образом
UpdateCommand = новый AsyncRelayCommand(Update, SomeCanExecuteMethod); ... ... частный bool SomeCanExecuteMethod() { вернуть _someDependency.DoSomethingAsync().Result; } Вопрос Теперь предположим, что мы сделали все так, как предполагалось при реализации DoSomethingAsync, и каждый вызов await правильно настроен с помощью ConfigureAwait(false). Может ли приведенная выше конструкция привести к тупику?
Альтернативный вариант
Предполагая, что ответ на вышеприведенный вопрос положительный, будет ли это всегда предотвращать потенциальную тупиковую ситуацию?
private bool SomeCanExecuteMethod() { вернуть Task.Run(async () => { return await _someDependency.DoSomethingAsync().ConfigureAwait(false); }).Результат; } Честно говоря, я не могу объяснить, почему это может решить проблему. Я кое-что помню (смутно), что это имеет своего рода побочный эффект: устанавливает для контекста синхронизации значение null, что, в свою очередь, предотвращает возникновение тупиковой ситуации.
Второй вариант
Поскольку альтернативный вариант (если он верен) немного напоминает «программирование с побочными эффектами», не лучше ли было бы указать явно и явно установить нулевой контекст синхронизации?
частный bool SomeCanExecuteMethod() { вар контекст = SynchronizationContext.Current; SynchronizationContext.SetSynchronizationContext(null); результат вар = _someDependency.DoSomethingAsync().Result; SynchronizationContext.SetSynchronizationContext(контекст); вернуть результат; }
ПРИМЕЧАНИЕ. Со смешением асинхронного и синхронного кода мы сталкиваемся чаще, чем только в этом примере MVVM. Нам также приходится иметь дело с наследием, которое в некоторых случаях просто слишком агрессивно, чтобы полностью выполнить рефакторинг для асинхронного ожидания. Поэтому мы ищем «серебряную пулю» для решения проблемы смешивания асинхронного и синхронного кода, если таковая имеется...
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение