有些文章指出异步数据库调用在.NET中是个坏主意。
在C#Async CTP上,有一个名为System.Data.SqlClient.SqlCommand
的{{1}}扩展名。我现有代码的操作如下:
ExecuteReaderAsync
我的代码上有几个这样的操作。所以,我正在考虑将这些转换为异步。
但另一方面,我对这种方法没有太大的吸引力(也许我没有看到正确的方向,谁知道!)。
那么,在这里使用这种新的异步编程模型有什么缺点吗?
修改
假设我重构代码如下:
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();
}
}
据我所知,从await关键字,它将代码转换为继续。此外,当它命中await关键字时,无论操作状态如何,它都会立即返回其调用者。完成后,它会返回并触发延续代码。
这就是我的想法。
答案 0 :(得分:54)
我不同意Ricka的观点。异步数据库命令不仅好,而且对于实现扩展,吞吐量和延迟至关重要。他对线程池增加时间的反对意见仅适用于流量较低的Web服务器。
在高流量情况下(这是唯一重要的),线程池不必等待“注入”新线程。异步执行SQL命令不仅从Web服务器请求/线程运行状况的角度来看很重要,而且从总请求生存期/延迟的角度来看也很重要:不相关的DB调用可以并行完成,而不是顺序完成。仅这一点通常会导致用户体验到的HTTP请求延迟的显着改善。换句话说,您的网页加载速度更快。
一句忠告:在您在连接字符串上启用Asynchronous Processing=true
之前,SQL命令不是真正的异步。虽然未设置(默认情况下不是,编辑:从.NET Framework开始< 4.5。Asynchronous Processing
is no longer required ),但对BeginExecuteReader
的“异步”调用只是假的,调用将启动一个线程并阻止那个线程。如果在连接字符串中启用了真正的异步处理,那么该调用将是真正的异步,并且回调基于IO完成。
请注意:只要第一个结果返回到客户端,异步SQL命令就会完成,并且信息消息会计为结果。
create procedure usp_DetailsTagsGetAllFromApprovedPropsWithCount
as
begin
print 'Hello';
select complex query;
end
你已经失去了异步的所有好处。 print
创建一个发送回客户端的结果,完成异步命令并在客户端上执行恢复并继续使用'reader.Read()'。现在 将阻塞,直到复杂查询开始产生结果。你问'谁把print
放在程序中?'但是print
可能会伪装成其他东西,或许是无辜的东西看起来像执行INSERT
没有首先发出SET NOCOUNT ON
。
答案 1 :(得分:0)
我注意到以下问题没有得到解答:
那么,在这里使用这种新的异步编程模型有什么缺点吗?
缺点 非常小(次要cpu /次要内存afaik),因为在await语句之后有可能运行任何代码可以在单独的线程上运行,存在状态机来存储当前运行的线程的状态,以便可以在另一个线程上处理继续工作。您可以阅读有关await/async statemachine on Dixin's Blog - Understanding C# async / await (1) Compilation。
的更多信息