ViewModel 中使用ConfigureAwait(false) 何时会出现问题?

ste*_*v-e 3 mvvm xamarin configureawait

我想知道在什么情况下使用时会遇到问题

ConfigureAwait(false)
Run Code Online (Sandbox Code Playgroud)

在我的(Xamarin)MVVM 方法中。这主要是因为我不完全理解视图和视图模型及其属性和底层模型之间的同步上下文......

1可观察集合呢?

// VM
public ObservableCollection<SomeThing> SomeThings { get; set; }
// ...
public Task InitWorkload()
{
    SomeThings = await DbService.GetSomeThings(); // <-- Should need synchronization context, doesn't it?
}

// Service
public Task<SomeThings> GetSomeThings()
{
    result = await CallToDb.ConfigureAwait(false); // <-- This is UI agnostic and shouldn't care about context or does it?
    return result;
}
Run Code Online (Sandbox Code Playgroud)

2导航怎么样(在本例中是在 FreshMvvm 的帮助下)?

private async Task CloseWindow()
{
    await CoreMethods.PopPageModel(); // <-- Should need synchronization context, doesn't it?
}
Run Code Online (Sandbox Code Playgroud)

jgo*_*SFT 6

回答标题问题“ ConfigureAwait(false)ViewModel 中的使用何时会出现问题?” 是“从不”。它在视图模型中的使用是无关紧要的。重要的是调用异步方法后您想要在哪个线程上运行,无论您是否在视图模型中都无关紧要。唯一可能出现ConfigureAwait(false)问题的情况是,如果您想返回到调用异步方法之前正在运行的线程。

作为参考,有关SynchronizationContext 类的文档。

也许解释什么ConfigureAwait(false)是回答这个问题的最佳方法。当像这样调用异步方法时:

var x = await SomeMethodAsync();
var y = x;
Run Code Online (Sandbox Code Playgroud)

该代码var y = x将在调用异步方法之前正在完成工作的同一线程上运行,即异步方法调用之前的同步上下文,但是如果您使用ConfigureAwait(false),例如:

var x = await SomeMethodAsync().ConfigureAwait(false);
var y = x;
Run Code Online (Sandbox Code Playgroud)

那么代码将在该方法返回时运行的var y = x同一线程上运行。SomeMethodAsync(大概SomeMethodAsync使用Task.Runor Thread.StartNewwhich 是启动新线程的主要方式...await不启动新线程,它只是语法糖,让你的异步代码更具可读性,以便异步方法调用后面的代码没有成为委托方法或 lambda,但可以像同步代码一样内联。)

因此,您需要什么取决于可能需要更新什么。任何 UI 更新都需要在主线程或 UI 线程上运行。您始终可以使用 来将代码编组到主线程或 UI 线程Device.BeginInvokeOnMainThread(Action)

一般来说,当您处于按钮单击处理程序事件中时,事件处理程序方法开始在 UI 线程上运行。如果您需要调用一个异步方法然后更新某些 UI,则不要使用ConfigureAwait(false),以便在异步方法之后返回到主/UI 线程并可以更新您的 UI。如果您不需要更新任何 UI,请随意调用,ConfigureAwait(false)这样当不需要在 UI 线程上运行时,您就不会不必要地返回到该线程。

在某些情况下,如果您从 UI 线程上启动的一个方法调用多个异步方法,您可能希望使用这样的ConfigureAwait(false)方法,这样就不会多次从后台线程来回切换到 UI 线程,这会导致性能问题,但是相反,所有非 UI 工作都是在后台线程上完成的,然后您只需在需要时手动封送回 UI 线程。

至于 an ObservableCollection,它没有线程亲和性,即当一个对象只能在创建它的同一线程上更新或修改时,但它也不是线程安全的,所以你最好的计划是只访问或更改ObservableCollection 位于创建它的同一线程上,很可能是主/UI 线程。