ASPNet Entity Framework 6 - EF6,在同一个工作单元中混合异步和同步

Posted

技术标签:

【中文标题】ASPNet Entity Framework 6 - EF6,在同一个工作单元中混合异步和同步【英文标题】:ASPNet Entity Framework 6 - EF6, mixing async and sync in the same unit of work 【发布时间】:2020-01-27 16:17:33 【问题描述】:

我今天遇到了几行代码,归结为如下:

using (var db = new AppDbContext())

    var foo = await db.Foos
        .Where(m => m.Name == "BuzzBaz" )
        .FirstAsync();

    foo.Name = "Quxx";
    db.SaveChanges();

请注意,选择查询是 async,但对 SaveChanges() 的调用不是。是同步的!

这可能会造成任何问题吗?我应该重构它以使用db.SaveChangesAsync(); 并且一切都很好吗?或者也许只是调用First() 而不是FirstAsync()?或者它可能是无害的并且可能对整体系统性能有一些好处?

我发现一些文档让我认为完全删除 async 可能是一个不错的选择。 https://docs.microsoft.com/en-us/ef/ef6/fundamentals/async

在大多数使用异步的应用程序中没有明显的好处,甚至可能是有害的。在提交之前使用测试、分析和常识来衡量异步在您的特定场景中的影响。

【问题讨论】:

【参考方案1】:

您的代码实际上是“正确的”,这意味着它没有根本缺陷。

让我们分析一下发生了什么,以及我的 2 美分:

查询数据库时(FirstAsync),使用await表示指令将按顺序执行,但线程不会被阻塞(异步调用),可以用于其他事情.这可能是一件好事,如果这是一个服务器应用程序,您可能希望您的线程能够在等待数据库响应时处理其他请求。

但是,使用非异步 SaveChanges 会阻塞线程。这本身不是错误,但由于它也是对 db 的 I/O 操作,它可能会阻塞线程一段时间。如果你也在这里await 使用异步版本,它确实看起来更“一致”。

这是个问题吗?这取决于。您的应用程序是否被大量使用?您的用户在重负载时是否遇到一些低反应?那么在这种情况下,在保存时使用异步可能是一个潜在的改进。

否则,正如链接的 MSDN 文章中所建议的那样,在您知道它有影响之前,我的建议是不要太担心。

混合使用本身不是问题。

就个人而言,我也会选择异步 SaveChanges,以保持一致性并想象 DB 写入是一些可能很慢的 I/O 操作。

如果是桌面应用程序,请确保您没有阻塞 UI 线程。

【讨论】:

使用await表示语句将异步执行,执行流程将返回给调用者。线程是否阻塞取决于调用者。 @PauloMorgado 我不确定要使用正确的词,但为了让其他读者清楚:async Task MainFunction() Console.WriteLine("before"); await Foo(); Console.WriteLine("after") async Task Foo() // long processing during several seconds ... and then : Console.WriteLine("processed!"): 将可靠地导致输出:“之前” ,“处理!”,“之后”。执行流程对我来说看起来很“同步”,await 所做的(使异步调用看起来与执行流程同步)。 你不是把顺序和同步搞混了吗? @PauloMorgado 最有可能!谢谢你的话,我会编辑我的答案【参考方案2】:

除了编码一致性(这非常重要)之外,请考虑以下几点:

    这是一个 DAL 库吗?你确定谁会使用它,你确定代码的可重用性永远不会成为问题吗?

如果答案是可能的,请坚持使用异步。前端 UI 将在保存期间被阻止,使其无响应。 Web API 使用 IO 线程来实现更好的线程管理:Simple description of worker and I/O threads in .NET

如果它是一个库,请确保将ConfigureAwait(false) 用于所有异步函数调用。

    即使使用 await,调用也是异步的,就在另一个线程上运行的 rubbing 而言,而原来的线程正在等待。大多数情况下,这作为性能可以忽略不计,但为什么不呢?

我通常将所有内容都设为异步,如果需要同步实现,我更喜欢使用同步版本制作代码副本。

【讨论】:

以上是关于ASPNet Entity Framework 6 - EF6,在同一个工作单元中混合异步和同步的主要内容,如果未能解决你的问题,请参考以下文章

如何告诉 Entity Framework 我的 ID 列是自动递增的(AspNet Core 2.0 + PostgreSQL)?

在 Entity Framework 7 RC 1 和 ASP.NET MVC 6 中播种初始数据 [重复]

向数据库添加新表后如何更新 Entity Framework Core

Entity Framework 6 暂时禁用拦截

Entity Framework Core 6.0 预览4 性能改进

Entity Framework 6 开发系列 目录