我在.NET 4.7.1上维护一个ASP.NET网站,它使用Entity Framework 6.0显示一些相当广泛的信息。现在,所有这些数据库查询都是串行执行的,所以我试图通过实现async / await来提高性能。
我遇到的问题是针对同一个数据库运行多个同时查询似乎有些微妙,而且我在搜索此类场景的任何最佳实践时遇到了问题。
网站的初始实现为环境事务中的每个查询创建了一个上下文,并在使用后处理了上下文。在将整个站点转换为使用异步(并注意TransactionScopeAsyncFlowOption.Enabled
)时,页面加载开始抛出声称需要配置分布式事务处理协调器的异常。
System.Transactions.TransactionManagerCommunicationException:分布式事务管理器(MSDTC)的网络访问已被禁用。
请使用组件服务管理工具在MSDTC的安全配置中启用DTC以进行网络访问。
在那一点上的一些搜索使我相信这可以在代码中得到纠正,而不会产生令人不安的配置,因此我接下来重新设计数据层以便以允许它们共享相同上下文的方式管理连接。但是,在测试该方法时,会抛出新的异常,声称连接太忙。
System.Data.SqlClient.SqlException:执行超时已过期。操作完成之前经过的超时时间或服务器没有响应。请求无法运行,因为批处理已中止,这可能是由客户端发出的中止信号引起的,或者是另一个请求在同一会话中运行,这会使会话忙。
通常此页面的加载时间很慢(几秒钟),但远不及默认的超时阈值。
只有当并行运行的查询连接到不同的数据库时,async / await才最适合吗?如果没有,MSDTC是启用此行为的唯一方法吗?或者,通过如此多的同步查询来爆炸单个数据库可能不是一件明智的事情吗?
答案 0 :(得分:1)
我无法准确理解您对该应用程序所做的更改。我也不确定该应用程序是否正确编写,并且遵循了合理的做法。但这里有一些我希望可以提供帮助的数据点:
EF中的异步支持旨在用于在等待I / O时将线程返回池,以便应用程序可以使用更少的线程和资源处理更多数量的请求。它并不意味着使用相同的DbContext启用并行执行。与.NET中的大多数类型一样,DbContext不是线程安全的(在任何版本的EF中),因此您无法在同一个上下文实例上并行安全地执行多个查询(异步或非异步)。
使用不共享状态或连接对象的单独DbContext实例应该没问题,但是建议在ASP.NET中,您仍然可以在任何时间点使用单个线程来处理请求(当你进行异步调用产生,处理可能在另一个线程上继续,但这不是一个问题)而不是试图在同一个请求中并行化工作。
此外,关于System.Transaction的异常,很可能你改变的东西现在导致多个连接在同一个System.Transactions.Transaction中自动登记,这可能需要将事务升级到分布式交易。
我不会尝试为超时提供完整的解释,因为正如我所说,我不确定我理解您对该应用程序所做的更改。但完全有可能的是,如果你创建太多的线程,其中一些线程最终将会挨饿并超时。如果你从多个线程开始使用类型不是线程安全的(例如数据库连接,DbContext),那么极难预测可能出错的一切。