.net 异步void方法未立即返回(EF6)
如果我将Initialise更改为使用wait Task.Run()调用同步this.db.Entities.Load(),则它会立即按预期返回。代码将执行到第一个等待点(对于尚未完成的数据)。请记住,.net 异步void方法未立即返回(EF6),.net,entity-framework,async-await,entity-framework-6,.net,Entity Framework,Async Await,Entity Framework 6,如果我将Initialise更改为使用wait Task.Run()调用同步this.db.Entities.Load(),则它会立即按预期返回。代码将执行到第一个等待点(对于尚未完成的数据)。请记住,初始化有效地: public class MyClass { MyEntities db = new MyEntities(); public MyClass() { this.Initialise(); // Does not return immedi
初始化
有效地:
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();
}
}
因此,我们必须得出结论,LoadAsync
在它产生之前花费了相当长的时间。这完全在API的限制范围内,await
API只会让事情变得可以等待;它不能保证所有的东西都是非阻塞的。例如,以下内容是完全可以期待的:
var tmp = this.db.Entities.LoadAsync();
await tmp;
静态任务邪恶(){
睡眠(60000);
返回任务.FromResult(4);
}
可能是数据上下文正在加载元数据、加载程序集等—在它知道是否可以生成之前。我认为延迟是由于第一次使用DbContext实例时实体框架正在预热。LoadAsync()方法可能仅异步执行数据库I/O。预热所花费的时间远远超过我的应用程序中的任何数据库查询。唯一的解决方案是在一个完整的Task.Run()中执行“预热查询”,然后对后续的异步方法使用wait。另一方面,最好避免
Async void
。我的博客上有一些。这个类是一个viewmodel,因此包含视图的其他状态信息,比如按钮是否启用。我需要立即返回构造的对象,否则视图将处于未定义状态。async方法只是填充在构建viewmodel时已经绑定的属性,并且数据异步显示在屏幕上。由于它是一个WPF应用程序,UI线程的同步上下文将捕获异常(与Windows Phone/Windows 8应用商店应用程序不同)。我理解这一点,并重申我的建议,即使用异步初始化方法。与async void
的唯一区别在于,您可以正确地处理错误(甚至可以通过数据绑定处理异常情况)。WP和Win8应用程序与WPF具有相同的async void
异常处理-它在UI线程的SyncContext
上引发。但如果你在那里处理异常,你就是在对局部问题应用全局解决方案。
static Task<int> Evil() {
Thread.Sleep(60000);
return Task.FromResult(4);
}