35

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

在 C# Async CTP 上,有一个System.Data.SqlClient.SqlCommand名为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();
    }
}

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

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

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

编辑:

假设我重构代码如下:

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 关键字了解,它将后面的代码转换为延续。此外,当它遇到 await 关键字时,无论操作状态如何,它都会立即返回给调用者。当它完成时,它会返回并触发延续代码。

这就是我的想法。

4

2 回答 2

61

我不同意 Ricka 的观点。Async 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做这个程序?” 但是 theprint可能会伪装成其他东西,也许看起来像在没有先发出 a 的情况下INSERT执行的一样无辜。SET NOCOUNT ON

于 2012-02-24T16:48:37.913 回答
0

I notice that the following question wasn't answered:

So, is there any disadvantages of using this new async programming model here?

The disadvantage which is very minimal (minor cpu/minor memory afaik), is that because there is the possibility of any code running after an await statement may run on a separate thread, a state-machine exists to store the state of the currently running thread so that the continuation of work can be handled on another thread. You can read more about the await/async statemachine on Dixin's Blog - Understanding C# async / await (1) Compilation.

于 2018-01-26T18:55:06.227 回答