mon*_*_za 3 .net c# sql asynchronous async-await
我有以下两种方法,它们产生相同的结果。
public static async Task<IEnumerable<RiskDetails>> ExecuteSqlStoredProcedureSelect<T>(IEnumerable<AccountInfo> linkedAccounts, string connectionString, string storedProcedure, int connTimeout = 10)
{
var responseList = new List<RiskDetails>();
using (IDbConnection conn = new SqlConnection(connectionString))
{
foreach (var account in linkedAccounts)
{
var enumResults = await conn.QueryAsync<RiskDetails>(storedProcedure,
new { UserID = account.UserID, CasinoID = account.CasinoID, GamingServerID = account.GamingServerID, AccountNo = account.AccountNumber, Group = account.GroupCode, EmailAddress = account.USEMAIL },
commandType: CommandType.StoredProcedure);
if (enumResults != null)
foreach (var response in enumResults)
responseList.Add(response);
}
}
return responseList;
}
public static async Task<IEnumerable<RiskDetails>> ExecuteSqlStoredProcedureSelectParallel<T>(IEnumerable<AccountInfo> linkedAccounts, string connectionString, string storedProcedure, int connTimeout = 10)
{
List<Task<IEnumerable<RiskDetails>>> tasks = new List<Task<IEnumerable<RiskDetails>>>();
var responseList = new List<RiskDetails>();
using (IDbConnection conn = new SqlConnection(connectionString))
{
conn.Open();
foreach (var account in linkedAccounts)
{
var enumResults = conn.QueryAsync<RiskDetails>(storedProcedure,
new { UserID = account.UserID, CasinoID = account.CasinoID, GamingServerID = account.GamingServerID, AccountNo = account.AccountNumber, Group = account.GroupCode, EmailAddress = account.USEMAIL },
commandType: CommandType.StoredProcedure, commandTimeout: 0);
//add task
tasks.Add(enumResults);
}
//await and get results
var results = await Task.WhenAll(tasks);
foreach (var value in results)
foreach (var riskDetail in value)
responseList.Add(riskDetail);
}
return responseList;
}
Run Code Online (Sandbox Code Playgroud)
我对如何ExecuteSqlStoredProcedureSelect执行的理解如下:
我对如何ExecuteSqlStoredProcedureSelectParallel执行的理解如下:
Task.WhenAll,这将开始执行帐户 #n 的查询根据我的理解,ExecuteSqlStoredProcedureSelectParallel这个功能在时间方面应该有一点改进,但目前还没有。
我对此的理解是否错误?
您的理解ExecuteSqlStoredProcedureSelectParalel并不完全正确。
调用 Task.WhenAll,这将开始执行帐户 #n 的查询
Task.WhenAll不启动任何东西。方法返回后QueryAsync- 任务已经开始并正在运行甚至完成。当控制到达时Task.WhenAll- 所有任务都已经开始。
查询相对于 SQL Server 并行执行
这是一个复杂的话题。为了能够在同一个 sql 连接上同时执行多个查询 - 您可以MultipleActiveResultSets在连接字符串中启用选项,否则将无法工作(抛出异常)。
然后,在许多地方,包括文档,您可以读到 MARS 与并行执行无关。它与语句交错有关,这意味着 SQL Server 可能会在同一连接上执行的不同语句之间切换,就像操作系统可能在线程(在单核上)之间切换一样。引用上述链接:
MARS 操作在服务器上同步执行。允许 SELECT 和 BULK INSERT 语句的语句交错。但是,数据操作语言 (DML) 和数据定义语言 (DDL) 语句以原子方式执行。在执行原子批处理时尝试执行的任何语句都会被阻止。服务器上的并行执行不是 MARS 的功能。
现在,即使您的选择查询在服务器上并行执行,如果这些查询执行速度很快,那么在“性能”方面也不会对您有太大帮助。
假设您查询 10 个帐户,每个查询执行需要 1 毫秒(很正常,我想说的是预期情况)。但是,每个查询返回 100 行。现在,这 100 行应该通过网络传递给调用者。这是成本最高的部分,与之相比,执行时间可以忽略不计(在这个特定的示例中)。无论您是否使用 MARS,您都只有一个与 sql server 的物理连接。即使您的 10 个查询在服务器上并行执行(由于上述原因我对此表示怀疑),它们的结果也无法并行传递给您,因为您只有一个物理连接。因此,在这两种情况下,10*100 = 1000 行都会“按顺序”传送给您。
由此应该清楚的是,您不应该期望您的Parallel版本执行速度明显更快。如果您希望它真正并行 -对每个命令使用单独的连接。
我还想补充一点,在这种情况下,计算机上的物理核心数量对性能没有不可忽略的影响。异步 IO 与阻塞线程无关,您可能在互联网上的很多地方读到过。