EF Core - 异步函数阻塞 UI

Posted

技术标签:

【中文标题】EF Core - 异步函数阻塞 UI【英文标题】:EF Core - Async functions are blocking UI 【发布时间】:2021-05-26 05:50:56 【问题描述】:

也许我错了,这实际上是好的行为,但是我不明白,为什么他们甚至会将异步后缀放在方法名称中并使其可等待。

只是为了轻松重现,这就足够了:

private async void Button_Click(object sender, RoutedEventArgs e)

    using var ctx = new eWMSContext();
    var a = await ctx.TJobLines.ToListAsync();

这个调用会阻止 UI,尽管它看起来不应该,并且将其包装到 Task.Run 似乎不合逻辑。

我找不到任何资源为什么会发生这种情况。

此资源解释说,它不应该阻止 UI,但它会: https://docs.microsoft.com/lt-lt/ef/core/miscellaneous/async

我正在使用(所有都是 .NET Core 3.1 的最新版本): EF Core 3.1.12 Oracle.EntityFrameworkCore 3.19.80 Oracle.ManagedDataAccess.Core 2.19.101

【问题讨论】:

ToListAsync()是其中唯一的 async 部分,并且大部分时间(和阻塞)发生在同步构造函数和属性获取器上。 有些相关:Why File.ReadAllLinesAsync() blocks the UI thread?。不幸的是,现实并不总是符合我们的期望。幸运的是,我们有 Task.Run 在需要时为我们提供帮助。 @PoulBak 你好,它真的没有。我做了测试,阻塞部分是 ToListAsync 本身。 FindAsync、FirstOrDefaultAsync 等的相同帐户...所有 EF Core 异步方法都阻塞了 UI。 另一个相关问题:Can the Oracle Managed Driver use async/wait properly? @TheodorZoulias 嘿,谢谢你的链接,大概就是这样......说实话有点难过。无论如何感谢这篇文章 【参考方案1】:

不幸的是,这些方法的实际实现似乎还有一些不足之处:

Why would an EF query with ToListAsync hang in a WPF application?

作为一种解决方法,为了让您的 UI 保持响应,您可以在后台线程上执行同步版本:

private async void Button_Click(object sender, RoutedEventArgs e)

    await Task.Run(() =>
    
        using var ctx = new eWMSContext()
        
            var a = ctx.TJobLines.ToList();
        
    );

那么您不必依赖ToListAsync 的实现是非阻塞的。

【讨论】:

+1。我建议将a 变量设为Task.Run 方法的结果,因为很可能OP 想用它来更新UI 控件。从 Task.Run 内部访问 UI 控件是一个容易犯的常见错误。 嗯,这很可悲。那他们为什么要实现异步功能呢?甚至像 FindAsync 一样,FirstOrDefaultAsync 块也是如此。这对我来说很伤心。我什至看不到使用异步等待的理由。 @TheodorZoulias 我正在使用 MVVM 和响应式 UI,单击此按钮实际上只是为了最简单地重现问题。 "他们为什么要实现异步函数呢?" -> 因为 ToListAsync 可以针对 any IQueryable 调用,而不管如何它被实施。您遇到了 Oracle 驱动程序的限制。使用 SQL Server 驱动程序(例如)调用 ToListAsync 不会阻塞。

以上是关于EF Core - 异步函数阻塞 UI的主要内容,如果未能解决你的问题,请参考以下文章

UIImage initWithData:从异步调度中阻塞 UI 线程?

异步代码是不是在 UI 线程或新/不同线程中运行以不阻塞 UI?

❲Linux环境开发❳:同异步阻塞的IO模型相关的问题

C# 理解阻塞 UI 和异步/等待与 Task.Run 的问题?

如何在 C# 中异步提取 zip 文件以不阻塞 UI?

在 SwiftUI 视图中发布后台上下文 Core Data 更改而不阻塞 UI