Чтобы ответить на заглавный вопрос, "Когда проблематично использование ConfigureAwait(false)
в ViewModels?"никогда."Его использование в модели представления не имеет значения.Важно то, в каком потоке вы хотите запускаться после вызова асинхронного метода, независимо от того, находитесь ли вы в модели представления или нет.Единственный случай, когда использование ConfigureAwait(false)
может быть проблематичным, это если вы хотите вернуться к потоку, который работал до вызова асинхронного метода.
И для справки, документы по классу SynchronizationContext .
Возможно, объяснение того, что делает ConfigureAwait(false)
, является лучшим подходом для ответа на этот вопрос.Когда кто-то вызывает асинхронный метод, например, так:
var x = await SomeMethodAsync();
var y = x;
Код var y = x
будет выполняться в том же потоке, над которым выполнялась работа до вызова асинхронного метода, то есть в контексте синхронизации доасинхронный вызов метода, однако, если вы используете ConfigureAwait (false), например:
var x = await SomeMethodAsync().ConfigureAwait(false);
var y = x;
, тогда код var y = x
будет выполняться в том же потоке, в котором выполнялся метод SomeMethodAsync
, когда он возвращался.(Предположительно SomeMethodAsync
использует Task.Run
или Thread.StartNew
, которые являются основными способами запуска нового потока ... await
не запускает новый поток, это всего лишь синтаксический сахар, позволяющий сделать ваш асинхронный код более читабельнымтак что код, следующий за вызовом асинхронного метода, не обязательно должен быть методом делегата или лямбда-выражением, а может быть встроенным, как синхронный код.)
То, что вам нужно, зависит от того, что должно бытьобновлено.Любые обновления пользовательского интерфейса должны выполняться в основном потоке или пользовательском интерфейсе.Вы всегда можете ввести код в основной поток или поток пользовательского интерфейса с помощью Device.BeginInvokeOnMainThread(Action)
.
Обычно, когда вы находитесь, скажем, в событии обработчика щелчка кнопки, метод обработчика события запускается в потоке пользовательского интерфейса.Если вам нужно вызвать один асинхронный метод, а затем обновить какой-либо пользовательский интерфейс, не используйте ConfigureAwait(false)
, чтобы после асинхронного метода вы вернулись в поток Main / UI и могли обновить свой пользовательский интерфейс.Если вам не нужно обновлять какой-либо пользовательский интерфейс, не стесняйтесь вызывать ConfigureAwait(false)
, чтобы вы не возвращались без необходимости в поток пользовательского интерфейса, когда в этом потоке нет необходимости.
В некоторых случаях, если вы вызываете несколько асинхронных методов из одного метода, который запускается в потоке пользовательского интерфейса, вы можете использовать ConfigureAwait(false)
, чтобы не переходить назад и вперед в поток пользовательского интерфейса из фоновых потоков.несколько раз, которые вызывают проблемы с производительностью, но, скорее, вся работа, не связанная с пользовательским интерфейсом, выполняется в фоновом потоке, а затем вы просто вручную выполняете маршалинг обратно в поток пользовательского интерфейса, когда и при необходимости.
Что касается ObservableCollection
, он не имеет привязки к потоку, т. Е. Когда объект может быть обновлен или изменен только в том же потоке, в котором он был создан, но он также не является потокобезопасным, поэтомуНаилучший план состоит в том, чтобы получить доступ к ObservableCollection или изменить ее только в том же потоке, в котором он был создан, скорее всего, в главном / пользовательском интерфейсе.