异步的await似乎使用的UI线程 [英] Async-await seems to use the UI thread

查看:251
本文介绍了异步的await似乎使用的UI线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一个视图模型我使用工厂:

In a view-model I use a factory:

private async Task<BaseData> InitializeAsync()
{
    await InstancesAsync();
    await ProjectsAsync();
    await AdminAsync();
    return this;
}
public static async Task<BaseData> CreateAsync()
{
    var ret = new BaseData();
    return await ret.InitializeAsync();
}

在期待已久的方法是相当staightforward,例如用

The awaited methods are rather staightforward, with e.g.

 var instances = await TaskEx.Run(new Func<List<string>>(() => Agent.GetInstances()));

在WPF观点我想设置的DataContext在构造函数中:

In the wpf view I want to set the DataContext in the constructor:

Loaded += delegate
{
    Dispatcher.Invoke(new Action(async () => { DataContext = await BasisGegevens.CreateAsync(); }));
};

虽然它的作品,我感到相当不舒服,因为使用UI线程的处处的,也回调后,当等待着完成。我缺少什么?

Although it works, I feel rather uncomfortable because the UI thread is used everywhere, also after the callbacks when the awaits complete. What am I missing?

此外,我不知道如何使用的的DataContext 因为没有调用工厂模式上面我得到不同的线程拥有该对象的错误。

Also I don't understand how to use the factory pattern for the DataContext because without the Invoke above I get the error that a different thread owns the object.

编辑:使用克利先生,我得到的想法:

using the ideas of Mr. Cleary I get:

Loaded += async (object sender, RoutedEventArgs e) =>
          { DataContext = await BaseData.CreateAsync(); };
public static Task<BaseData> CreateAsync()
{
    var ret = new BaseData();
    return ret.InitializeAsync();
}
private async Task<BaseData> InitializeAsync()
{
    // UI thread here
    await InstancesAsync().ConfigureAwait(false);
    // thread 'a' here
    await ProjectsAsync().ConfigureAwait(false);
    // thread 'a' sometimes 'b' here
    await AdminAsync().ConfigureAwait(false);
    // thread 'a' or 'b' here
    return this;
}

这工作正常,但我无法理解如何 ConfigureAwait(假)的作品。结果
里面的方法 InstancesAsync()我有期待已久的任务:结果
VAR实例=等待TaskEx.Run(新Func键&LT;名单,LT;串GT;&GT;(()=&GT; Agent.GetInstances())); 结果
等待repsonse后,我在UI线程返回 - 我没想到这样的事情发生结果!
需要注意的是 ProjectsAsync() AdminAsync()的功能相同,但他们开始在一个工人(或背景)线程!结果
我那吼声 ConfigureAwait(真)在调用线程返回的效果(在我的情况UI线程)。我测试了一下它是如此。结果
为什么我看到这个用 ConfigureAwait(假)太:因为一个嵌套伺机,看评论

This works fine, except I cannot understand how ConfigureAwait(false) works.
Inside the method InstancesAsync() I have the awaited task:
var instances = await TaskEx.Run(new Func<List<string>>(() => Agent.GetInstances()));
After awaiting the repsonse, I return in the UI thread - I never expected that to happen!
Note that ProjectsAsync() and AdminAsync() behave the same, although they start on a worker (or background) thread!
I thougth that ConfigureAwait(true) has the effect of returning in the calling thread (in my case UI thread). I tested that and it is so.
Why do I see this with ConfigureAwait(false) too: because of a nested await, see comments.

推荐答案

我觉得最有用的治疗视图模型具有UI线程亲和力。把它看成是逻辑的用户界面,即使它不是的实际的UI。因此,对视图模型类的所有财产和观察的集合更新应该在UI线程来完成。

I find it most useful to treat the ViewModel as having UI thread affinity. Think of it as the logical UI, even if it's not the actual UI. So all property and observable collection updates on ViewModel classes should be done on the UI thread.

在你的异步方法,如果你不需要返回到UI线程,那么你可以使用 ConfigureAwait(假)来避免恢复UI线程上。例如,如果你的各种初始化方法是独立的,你可以做这样的事情:

In your async methods, if you don't need to return to the UI thread, then you can use ConfigureAwait(false) to avoid resuming on the UI thread. For example, if your various initialization methods are independent, you could do something like this:

private async Task<BaseData> InitializeAsync()
{
  // Start all methods on the UI thread.
  var instancesTask = InstancesAsync();
  var projectsTask = ProjectsAsync();
  var adminTask = AdminAsync();

  // Await for them all to complete, and resume this method on a background thread.
  await Task.WhenAll(instancesTask, projectsTask, adminTask).ConfigureAwait(false);

  return this;
}

此外,任何时候你有返回待机,再看看,看看你可以避开异步 / 的await 完全

Also, any time you have return await, take another look to see if you can just avoid async/await entirely:

public static Task<BaseData> CreateAsync()
{
  var ret = new BaseData();
  return ret.InitializeAsync();
}

最后,你应该极力避开调度。你的加载事件可以简化为这样的:

Finally, you should strongly avoid Dispatcher. Your Loaded event could be simplified to this:

Loaded += async ()
{
  DataContext = await BasisGegevens.CreateAsync();
};

这篇关于异步的await似乎使用的UI线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆