【问题标题】:ASPNet Entity Framework 6 - EF6, mixing async and sync in the same unit of workASPNet Entity Framework 6 - EF6,在同一个工作单元中混合异步和同步
【发布时间】: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

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

【问题讨论】:

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


    【解决方案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】:

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

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2015-03-23
      • 1970-01-01
      • 2017-03-18
      • 1970-01-01
      • 2014-01-04
      • 2013-11-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多