ASPNet 实体框架 6 - EF6,在同一工作单元中混合异步和同步



我今天遇到了几行代码,归根结底,相当于这样:

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://learn.microsoft.com/en-us/ef/ef6/fundamentals/async

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

你的代码,因为它是"正确的",这意味着它没有根本的缺陷。

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

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

  • 但是,使用非异步SaveChanges会阻塞线程。这本身不是错误,但由于它也是数据库上的 I/O 操作,因此它可能会在相当长的一段时间内阻塞线程。如果您也在这里使用异步版本await,它确实会看起来更"一致"。

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

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

用法的混合本身不是问题。

就个人而言,我也会选择异步保存更改,以实现一致性并想象数据库写入是一些可能很慢的 I/O 操作。

如果是桌面应用程序,只需确保未阻止 UI 线程即可。

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

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

如果答案是可能的,请坚持异步使用。前端 UI 将在保存期间被阻止,使其无响应。 Web API 利用 IO 线程,实现更好的线程管理:.NET 中工作线程和 I/O 线程的简单说明

如果是库,请确保对所有异步函数调用使用该ConfigureAwait(false)

  1. 即使使用 await,调用也是异步的,就像在另一个线程上运行摩擦一样,而原始线程正在等待。大多数时候,这作为性能可以忽略不计,但为什么不呢?

我通常使所有内容都是异步的,如果需要同步实现,我更喜欢使用同步版本使代码重复。

最新更新