从C#AsyncCTP使用ExecuteReaderAsync的任何缺点

有一些文章指出异步数据库调用在.NET中是个坏主意。

  • 我的数据库调用应该是异步的吗?
  • 我的数据库调用应该是异步第二部分

在C#Async CTP上,有一个名为ExecuteReaderAsyncSystem.Data.SqlClient.SqlCommand扩展。 我在现有代码上有如下操作:

 var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["hubConnectionString"].ConnectionString; using (var conn = new SqlConnection(connectionString)) { using (var cmd = new SqlCommand()) { cmd.Connection = conn; cmd.CommandText = "sp$DetailsTagsGetAllFromApprovedPropsWithCount"; cmd.CommandType = System.Data.CommandType.StoredProcedure; conn.Open(); var reader = cmd.ExecuteReader(); while (reader.Read()) { //do the reading } conn.Close(); } } 

我的代码上有几个这样的操作。 所以,我正在考虑将这些转换为异步。

但另一方面,我对这种方法没有太多的吸引力(也许我没有看到正确的方向,谁知道!)。

那么,在这里使用这种新的异步编程模型有什么缺点吗?

编辑:

假设我重构代码如下:

 public async Task<IEnumerable> GetDataAsync() { List foos = new List(); var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["hubConnectionString"].ConnectionString; using (var conn = new SqlConnection(connectionString)) { using (var cmd = new SqlCommand()) { cmd.Connection = conn; cmd.CommandText = "sp$DetailsTagsGetAllFromApprovedPropsWithCount"; cmd.CommandType = System.Data.CommandType.StoredProcedure; conn.Open(); var reader = await cmd.ExecuteReaderAsync(); while (reader.Read()) { //do the reading //create foos } conn.Close(); } } return foos; } 

据我所知,从await关键字,它将代码转换为继续。 此外,当它命中await关键字时,无论操作状态如何,它都会立即返回其调用者。 当它完成后,它会返回并触发延续代码。

这就是我的想法。

我不同意Ricka的观点。 异步数据库命令不仅好,它们在实现扩展,吞吐量延迟方面至关重要。 他对线程池增加时间的反对意见仅适用于流量较低的Web服务器。

在高流量情况下(这是唯一重要的),线程池不必等待“注入”新线程。 异步执行SQL命令不仅从Web服务器请求/线程运行状况的角度来看很重要,而且从总请求生存期/延迟的角度来看也很重要:不相关的DB调用可以并行完成,而不是顺序完成。 仅这一点通常会导致用户体验到的HTTP请求延迟的显着改善。 换句话说,您的网页加载速度更快。

但是请注意:在连接字符串上启用Asynchronous Processing=true之前,SQL命令不是真正的异步。 虽然没有设置(默认情况下不是这样, 编辑:从.NET Framework <4.5开始。 不再需要Asynchronous Processing )你对BeginExecuteReader ‘asyncronous’调用只不过是假的,调用将启动一个线程并阻塞那个post。 如果在连接字符串中启用真正的异步处理则该调用实际上是异步的,并且回调基于IO完成。

需要注意的是:一旦第一个结果返回到客户端,异步SQL命令就会完成,并且信息消息会计为结果。

 create procedure usp_DetailsTagsGetAllFromApprovedPropsWithCount as begin print 'Hello'; select complex query; end 

你已经失去了异步的所有好处。 print创建一个发送回客户端的结果,完成异步命令并在客户端上执行恢复并继续使用’reader.Read()’。 现在,这将阻止复杂查询开始生成结果。 你问‘谁把print放在手术中?’ 但是print可能是伪装成其他东西,也许是无辜的东西,看起来像是在没有先发出SET NOCOUNT ON 情况下执行的INSERT

我注意到以下问题没有得到解答:

那么,在这里使用这种新的异步编程模型有什么缺点吗?

非常小缺点 (次要cpu /次要内存afaik),是因为在await语句可能在单独的线程上运行后有可能运行任何代码,存在状态机来存储当前运行的状态线程,以便可以在另一个线程上处理继续工作。 您可以在Dixin的博客上了解有关await / async statemachine的更多信息- 了解C#async / await(1)编译 。