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

本文关键字:任何 缺点 ExecuteReaderAsync C#AsyncCTP 中的 使用 | 更新日期: 2023-09-27 18:25:37

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

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

在C#异步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<Foo>> GetDataAsync() { 
    List<Foo> foos = new List<Foo>();
    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关键字了解,它将后面的代码转换为continuation。此外,当它命中wait关键字时,无论操作状态如何,它都会立即返回给调用者。当它完成时,它会返回并激发延续代码。

这就是我的想法。

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

我不同意瑞卡的观点。异步DB命令不仅很好,而且在实现规模、吞吐量延迟方面至关重要。他对线程池的提升时间的反对意见仅适用于流量较低的web服务器。

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

不过,有一点建议:在连接字符串上启用Asynchronous Processing=true之前,SQL命令并不是真正的异步命令。虽然未设置(默认情况下也未设置),但编辑:从.NET Framework<4.5开始。不再需要Asynchronous Processing)如果对BeginExecuteReader的"异步"调用只是一个骗局,则该调用将启动一个线程并阻止该线程。如果在连接字符串中启用了真正的异步处理,则调用是真正的异步,回调基于IO完成。

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

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

您已经失去了异步的所有好处。print创建一个结果,并将其发送回客户端,从而完成异步命令,客户端上的执行将恢复并使用"reader.Read()"继续。现在,将阻止该结果,直到复杂查询开始产生结果。你问‘谁把print放在程序中?’,但print可能被伪装成其他东西,可能看起来像INSERT一样无辜,它执行没有首先发布SET NOCOUNT ON

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

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

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