【发布时间】:2019-08-01 03:33:00
【问题描述】:
System.Data.SqlClient 命名空间中可用的本机 *Async 方法有什么好处?与仅包含同步方法调用的主体的手动 Task.Run 相比,它们有什么优势?
这是我的“起点”示例(控制台应用程序):
using System;
using System.Data.SqlClient;
using System.Threading.Tasks;
class Program
{
const string CommandTest = @"
SET NOCOUNT ON;
WITH
L0 AS (SELECT c FROM (SELECT 1 UNION ALL SELECT 1) AS D(c)), -- 2^1
L1 AS (SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B), -- 2^2
L2 AS (SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B), -- 2^4
L3 AS (SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B), -- 2^8
L4 AS (SELECT 1 AS c FROM L3 AS A CROSS JOIN L3 AS B), -- 2^16
L5 AS (SELECT 1 AS c FROM L4 AS A CROSS JOIN L4 AS B), -- 2^32
Nums AS (SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS k FROM L5)
SELECT
k
FROM
Nums
WHERE
k <= 1000000";
const string ConnectionString = "Server=.;Database=master;Integrated Security=SSPI;";
// This requires c# 7.1 or later. Check project settings
public static async Task Main(string[] args)
{
var aSW = new System.Diagnostics.Stopwatch();
aSW.Restart();
{
var aRes = ExecuteSync();
Console.WriteLine($"ExecuteSync returned {aRes} in {aSW.Elapsed}.");
}
aSW.Restart();
{
var aRes = await ExecuteWrapperAsync();
Console.WriteLine($"ExecuteWrapperAsync returned {aRes} in {aSW.Elapsed}.");
}
aSW.Restart();
{
var aRes = await ExecuteNativeAsync();
Console.WriteLine($"ExecuteNativeAsync returned {aRes} in {aSW.Elapsed}.");
}
}
private static Task<long> ExecuteWrapperAsync()
{
return Task.Run(() => ExecuteSync());
}
private static long ExecuteSync()
{
using (var aConn = new SqlConnection(ConnectionString))
using (var aCmd = new SqlCommand(CommandTest, aConn))
{
aConn.Open();
using (var aR = aCmd.ExecuteReader())
{
long aRetVal = 0;
while (aR.Read())
aRetVal += aR.GetInt64(0);
return aRetVal;
}
}
}
private static async Task<long> ExecuteNativeAsync()
{
using (var aConn = new SqlConnection(ConnectionString))
using (var aCmd = new SqlCommand(CommandTest, aConn))
{
await aConn.OpenAsync();
using (var aR = await aCmd.ExecuteReaderAsync())
{
long aRetVal = 0;
while (await aR.ReadAsync())
aRetVal += aR.GetInt64(0);
return aRetVal;
}
}
}
}
谈到我的开发机器的性能,使用*Async 方法实际上会导致运行时间变慢。通常,我的输出如下:
ExecuteSync returned 500000500000 in 00:00:00.4514950.
ExecuteWrapperAsync returned 500000500000 in 00:00:00.2525898.
ExecuteNativeAsync returned 500000500000 in 00:00:00.3662496.
换句话说,方法ExecuteNativeAsync 是使用System.Data.SqlClient 的*Async 方法的方法,并且通常比由Task.Run 调用包装的同步方法慢。
我做错了吗?也许我误读了文档?
【问题讨论】:
-
为什么你认为异步运行一个方法会使其更快?
-
您的结果显示 ExecuteSync 最慢。如果您只是要立即
await它,那么调用 Async 方法并没有多大意义。关键是你可以在它执行的时候做其他事情。 -
@stuartd 我认为不应该。我通常对其他可能的好处感兴趣。例如,可以想象一个迁移场景。切换到
*Async有什么好处?在性能方面,我没有看到任何好处。另外还有更多的代码重写。但是,也许还有其他好处?我很感兴趣那些可能是什么,就是这样。 -
@Kerido 使用
async的重点更多是关于服务器处于压力下时的可伸缩性;在低负载下,async会比普通的同步调用增加更多的开销,但实际上async增加的小开销在服务器负载过重时是值得的。 -
@Blorgbeard 我正在尝试实现一个“实用的数据库读取场景”,很难想象与此数据库读取相关的行之间的任何侧面逻辑。你能不能想一想?
标签: c# sql-server async-await ado.net