Open 和 OpenAsync (SqlConnection) 之间的区别

Posted

技术标签:

【中文标题】Open 和 OpenAsync (SqlConnection) 之间的区别【英文标题】:Difference between Open and OpenAsync (SqlConnection) 【发布时间】:2017-05-27 02:40:25 【问题描述】:

(标题看起来类似于SqlConnection.Open vs SqlConnection.OpenAsync - what's different between the two beyond the obvious?,但a.它没有任何答案,b.我的情况下的观察结果不同)

在对 asp.net 服务中的性能问题进行基准测试时,我无意中发现了一个奇怪的现象,SqlConnection.Open 的性能远远好于SqlConnection.OpenAsync(更多详情见下文)。

从源代码here 看起来Open 的代码只是OpenAsync 的一个子集。差异here

我很好奇OpenOpenAsync 做的事情完全一样,使用异步版本(如果有的话)有什么好处?

详情:

这就是我创建连接的方式

using (SqlConnection connection = new SqlConnection(connectionString))

    await connection.OpenAsync();
    // run actual operation on connection (in an async way)

这个代码块需要 13 seconds on an average for 100 concurrent calls。我尝试将线程池计数增加到 200,以减少 tasks 等待线程的机会。即使在让默认线程池计数之后,观察结果也不会改变。

有趣的是,如果我将await connection.OpenAsync() 更改为connection.Open(),性能会提高10 倍。 1.01 seconds on an average of 100 concurrent calls

我尝试使用 connection pool settings 并看起来即使我将它减少到一个任意低的数字(2 是测试的),这个数字也不会发生太大变化。

驱动代码为:

Task.WhenAll(Enumerable.Range(0, maxConcurrentCalls).Select((idx) => CallQuery(idx))).Result;

我等待的原因(通过执行.Result 是因为驱动程序代码是一个控制台应用程序,它必须具有同步main)。在实际的生产代码中,包括控制器在内的所有内容都是async

【问题讨论】:

async 不会让任何事情变得更快。事实上,它会产生一些开销,这通常会使其变慢。它只是在等待某事(例如 IO 或 DB)完成时释放线程以进行其他操作。 @smoksnes 我知道这一点。我的意思是,当你的同步方法很重时,通常你会想要一个异步等效项。所以你卸载到一个单独的线程。至少从代码来看,openasync 并没有做任何比 open 更少的事情 我明白了。我对你的性能测量感到困惑。但是,如果您阅读代码,则有一个区别。 OpenAsyncTaskCompletionSource<DbConnectionInternal> 传递给 TryOpen。最终到达使用线程的TryGetConnection 你能分享你用来衡量这个的所有代码吗?您是否有机会同步等待您的 async 方法完成? @svick 我用两种方式测量它。一,我在 PaaS 上部署了一个纯异步的服务(使用异步控制器等)。我打电话给那个端点并测量统计数据。我看到与问题类似的结果。我正在向使用控制台应用程序测量上述数据的问题添加第二种方法。 【参考方案1】:

我使用 OpenAsync 的一种方法是,如果我打开了与多个数据库的连接。

Task t = conn1.OpenAsync();
conn2.Open();
t.Wait();

如果与远程服务器的连接速度较慢,则打开可能需要几秒钟。这样,两个 Open 是并行进行的。

【讨论】:

在blocking on async code 之上,这是额外的混乱,与问题无关。一次从同一个地方打开两个连接的正确方法是await Task.WhenAll(conn1.OpenAsync(), conn2.OpenAsync())

以上是关于Open 和 OpenAsync (SqlConnection) 之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

C# CancellationToken 如何与 SqlConnection.OpenAsync(token) 一起使用?

Datatable更新数据库

如何在 .NET 中取消 Task.Wait() 之后正在运行的 OpenAsync()?

Dicom文件基本操作

用truncate清空数据库表所有的数据用C#怎么写啊?

用 DataTable 填充的 SqlDataAdapter 不起作用