C# Web应用程序中的数据访问应该在不同的任务上运行吗?

C# Web应用程序中的数据访问应该在不同的任务上运行吗?,c#,asp.net,multithreading,asynchronous,asp.net-web-api,C#,Asp.net,Multithreading,Asynchronous,Asp.net Web Api,我正在编写一系列ASP.NETWebAPI服务,它们基本上从数据库获取数据并返回数据 我们现在决定重用以前编写得很差的数据访问对象(我们称它们为PoorDAO),它们使用ADO.Net调用数据库中的存储过程 未来的一个改进是重写数据访问层,以从实体框架中获益 因此,我们决定在存储库中封装PoorDAO,实现一个公开异步方法的接口。其想法是为未来的EF异步存储库保留相同的接口: //未来的通用接口 公共接口ICountryRepository { 任务GetAllCountries(); } //

我正在编写一系列ASP.NETWebAPI服务,它们基本上从数据库获取数据并返回数据

我们现在决定重用以前编写得很差的数据访问对象(我们称它们为
PoorDAO
),它们使用ADO.Net调用数据库中的存储过程

未来的一个改进是重写数据访问层,以从实体框架中获益

因此,我们决定在存储库中封装
PoorDAO
,实现一个公开异步方法的接口。其想法是为未来的EF异步存储库保留相同的接口:

//未来的通用接口
公共接口ICountryRepository
{
任务GetAllCountries();
}
//当前实现隐藏了一个羞耻的穷人
公共类CountryRepository:ICountryRepository
{
公共任务GetAllCountries()
{
var countries=PoorCountryDAO.GetAllcountries();//静态API调用不好
//一些数据转换。。。
返回Task.FromResult(结果);
}
}
我们这里基本上是一个隐藏在异步衣服中的同步操作。这一切都很好,但我的问题是:当我们这样做的时候,让方法完全异步并调用
wait Task.Run(()=>poorCountryDAO.GetAllcountries())
而不仅仅是
poorCountryDAO.GetAllcountries()

据我所知,这将释放Web Api服务HTTP请求当前运行的IIS线程,并创建或重用另一个线程。此线程将在等待DB响应时被阻塞,而不是IIS线程被阻塞。这是更好的资源明智吗?我是否完全误解或过度解释了Task.Run()的工作原理


Edit:我遇到过这样一种说法,即在某些情况下,异步数据库调用可以将性能提高8倍。他的情况和我的非常相似。在这里给出答案后,我无法理解这是怎么可能的,我有点困惑该怎么做…

这是同样的事情,你在锁定一个线程的同时释放另一个线程。理论上,性能是一样的,但实际上会因为上下文切换的开销而稍差一些:首先,对于
等待Task.Start(()=>poorCountryDAO.GetAllcountries())
Task.Start(()=>poorCountryDAO.GetAllcountries())
已经给了您一个任务,所以你应该把它退回,而不是等待

请注意,在任何情况下,此方法的
任务
实际上是同步的,这是一个实现细节。在后台线程中封装
GetAllCountries()
调用本身可能会有诱惑,但这不是一个好主意

在所有这些情况下,你仍然会被困在浪费线程。您希望完全释放IIS线程的场景要求对数据库调用使用“重叠IO”(根据您的链接)

基本上,在这些情况下,线程(主线程或工作线程)在调用
PoorCountryDAO.GetAllcountries()
时会阻塞。但是,当您切换到异步DB调用时,它们将不再烧线程。但是,如果调用方使用了自己的Task.Run,那么它现在会回来咬你

这是更好的资源明智吗

没有;事实证明,情况更糟。现有的
任务。FromResult
wait
是最佳解决方案


ASP.NET应用程序中不应使用
Task.Run
Task.Factory.StartNew
Task.Start
。它们从ASP.NET使用的同一线程池中窃取线程,导致额外的线程切换。此外,如果它们是长时间运行的,它们将干扰默认的ASP.NET线程池启发式,可能导致它不必要地创建和销毁线程。

您的建议没有任何区别,可能更糟。@MarkSowul“poorCountryDAO.GetAllcountries())已经给了您一个任务”:从我的描述中可能不清楚,但不,该方法不是异步的。这是一个来自遗留类的传统静态方法。@guillaume31我将调用web服务的客户端与调用API的web服务混为一谈;这似乎很有道理,但有些人认为情况并非总是如此(见我的编辑)。我现在有点困惑:/n使用异步数据库调用与使用
任务完全不同。运行
来包装同步数据库调用。异步数据库调用非常好,应该使用它(您提到您已经计划在将来这样做)。但是您不应该使用
Task.Run
来包装同步数据库调用。异步数据库调用:这是作者在SqlCommand上使用简单的
AsynchronousProcessing=true
所做的吗?我仍然不清楚它与EF的异步查询和保存之间的联系。文档中几乎没有关于
AsynchronousProcessing=true
的含义的信息,文章作者也没有回应,您知道我在哪里可以找到更多关于SQL server数据提供程序如何处理该选项的内部细节吗?异步db调用类似于
ExecuteReaderAsync