等待DbContext时WPF UI阻塞

时间:2015-09-29 03:50:53

标签: c# wpf entity-framework async-await

我正在尝试异步等待,而且我遇到了不应该发生的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<User> 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。

4 个答案:

答案 0 :(得分:2)

SQL Server CE中使用的连接对象不是threadsafe(自然异步API未实现)。我相信你正在遇到SQL CE的这个问题,因为它在创建DbContext的线程上执行,并且在等待时不将控制权返回给UI线程。尝试在DbContext内实例化Task并等待结果。

LoadButton.IsEnabled = false;

var users = await Task.Run(() => 
{
    using(TestContext ctx = new TestContext())
    {
        return ctx.Users.ToList();
    }
});

LoadButton.IsEnabled = true;

答案 1 :(得分:2)

似乎SQL Server Compact ADO.NET提供程序不提供异步API以及它阻塞的原因。我无法找到关于此的确切来源,但this answer明确说明了这一点。

答案 2 :(得分:1)

我相信ui被这条线阻挡

using(TestContext ctx = new TestContext())

尝试这样的事情(只是为了检查这是问题)

await Task.Run(() => {using(TestContext ctx = new TestContext())
    {
        IList<User> users = ctx.Users.ToList();
    }})

答案 3 :(得分:-2)

await 仅适用于使用 async 关键字定义的函数,并且 Task 作为返回类型。

在第一个场景中,Task.Delay(2000)将返回Timespan,因此等待没有任何影响。

虽然在第二个场景中 ctx.Users.ToListAsync()返回一个Task,然后我们调用await,这会导致阻塞当前(UI)线程。

有关详细信息,请参阅Microsoft的link