等待DbContext时WPF UI阻塞
我正在尝试异步等待,我遇到了不应该发生的UI阻塞。
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); LoadButton.Click += LoadButton_OnClick; } private async void LoadButton_OnClick(object sender, RoutedEventArgs e) { LoadButton.IsEnabled = false; // await Task.Delay(2000); using(TestContext ctx = new TestContext()) { IList users = await ctx.Users.ToListAsync(); } LoadButton.IsEnabled = true; } }
如果我评论DbContext位并取消注释Task.Delay,它会按预期运行 – 不阻止UI。
根据我的理解,仍然从UI线程调用ToListAsync()方法,但不应阻止它。 即使该方法受CPU限制(可能不是),也会导致延迟,而不是完整的阻塞。
我的问题:
我能正确理解吗?
为什么我的UI在等待ToListAsync()时会阻塞?
编辑
我尝试在调用此方法之前进行数据库调用以加热所有内容并确保它不会阻止建立第一个连接。 此外,我尝试将几千个条目添加到DbSet并等待SaveChangesAsync,同样的事情发生 – UI完全冻结几秒钟。
编辑2
我尝试了另一个使用相同代码的示例,它似乎正在工作。 不同之处在于,在第一个示例中,我使用的是Code First和SQL CE以及工作示例Database First和SQL Server。
SQL Server CE中使用的连接对象不是线程安全的 (未实现自然的异步API)。 我相信你正在遇到SQL CE这个问题,因为它在创建DbContext
的线程上执行,并且在等待时不将控制权返回给UI线程。 尝试在Task
实例化DbContext
并等待结果。
LoadButton.IsEnabled = false; var users = await Task.Run(() => { using(TestContext ctx = new TestContext()) { return ctx.Users.ToList(); } }); LoadButton.IsEnabled = true;
似乎SQL Server Compact ADO.NET提供程序不提供异步API,这就是它阻塞的原因。 我无法找到关于此的确切来源,但这个答案清楚地说明了这一点。
我相信ui被这条线阻挡了
using(TestContext ctx = new TestContext())
尝试这样的事情(只是为了检查这是问题)
await Task.Run(() => {using(TestContext ctx = new TestContext()) { IList users = ctx.Users.ToList(); }})
await
仅适用于使用async
关键字定义的函数,并且具有返回类型的Task
。
在第一个场景中, Task.Delay(2000)
将返回Timespan,因此等待没有任何影响。
在第二种情况下, ctx.Users.ToListAsync()
返回一个Task,然后我们调用await,这会导致阻塞当前(UI)线程。
有关更多详细信息,请参阅Microsoft的链接 。