【问题标题】:async void method not returning immediately (EF6)async void 方法不立即返回(EF6)
【发布时间】:2013-05-12 08:43:19
【问题描述】:
public class MyClass
{
    MyEntities db = new MyEntities();

    public MyClass()
    {
        this.Initialise(); // Does not return immediately. Why?
    }

    private async void Initialise();
    {
        await this.db.Entities.LoadAsync();
    }
}

如果我将 Initialise 更改为使用 await Task.Run() 来调用同步的 this.db.Entities.Load() 那么它会立即按预期返回。

【问题讨论】:

  • 附带说明,最好避免使用async void。我的博客上有一些alternative approaches to async initialization
  • 这个类是一个视图模型,因此包含视图的其他状态信息,例如按钮是否启用。我需要立即返回构造的对象,否则视图将处于未定义状态。 async 方法只是填充在构造视图模型时已经绑定的属性,并且数据异步显示在屏幕上。由于它是 WPF 应用程序,因此将在 UI 线程的同步上下文中捕获异常(与 Windows Phone / Windows 8 应用商店应用程序不同)。
  • 我理解并重申我的建议,即您使用异步初始化方法。与async void 的唯一区别是您可以正确处理错误(甚至可以通过数据绑定处理异常情况)。 WP 和 Win8 应用程序具有与 WPF 相同的 async void 异常处理 - 它在 UI 线程的 SyncContext 上引发。但是,如果您在那里处理异常,您就是将全局解决方案应用于本地问题。

标签: .net entity-framework async-await entity-framework-6


【解决方案1】:

代码将一直执行到第一个等待点(对于尚未完成的数据)。请记住,Initialise 实际上是:

var tmp = this.db.Entities.LoadAsync();
await tmp;

所以我们必须得出结论,LoadAsync 在它屈服之前花费了不小的时间。这完全在 API 限制之内——await API 只有助于使事情变得可等待;它不能保证一切都是非阻塞的。例如,以下是完全可以等待的:

static Task<int> Evil() {
    Thread.Sleep(60000);
    return Task.FromResult(4);
}

可能是数据上下文正在加载元数据、加载程序集等 - 在它知道它是否可以屈服之前。

【讨论】:

  • 我相信延迟是由于实体框架在第一次使用 DbContext 实例时预热。 LoadAsync() 方法可能只是异步执行数据库 I/O。预热时间比我的应用程序中的任何数据库查询要长得多。唯一的解决方案是在完整的 Task.Run() 中执行“预热查询”,然后将 await 用于后续的 Async 方法。
猜你喜欢
  • 2014-01-14
  • 1970-01-01
  • 1970-01-01
  • 2015-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-30
  • 2017-12-11
相关资源
最近更新 更多