cco*_*ook 10 c# ado.net asynchronous
编辑:这归结为为什么只更改SqlConnection.Open()以等待异步代码中的SqlConnection.OpenAsync()导致强烈不同的行为.
除了明显的异步行为之外,同步代码中的SqlConnection.Open调用与等待SqlConnection.OpenAsync调用的异步代码有什么区别?底层连接是否与数据库异步?
OpenAsync上的文档是精简版,https: //msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.openasync%28v=vs.110%29.aspx?f = 255 & MSPPError = -2147217396 .
Open的异步版本,它使用ConnectionString指定的设置打开数据库连接.此方法使用CancellationToken.None调用虚方法OpenAsync.(继承自DbConnection.)
我觉得有趣的是,之前连接字符串需要async = true,而在.net 4.5+中则不再需要.连接的行为是否不同?
https://msdn.microsoft.com/en-us/library/hh211418(v=vs.110).aspx
从.NET Framework 4.5开始,这些方法不再需要在连接字符串中使用Asynchronous Processing = true.
当我碰巧在异步应用程序中使用同步SqlConnection.Open并加载它时,我发现它执行得非常糟糕,早期运行连接池.我希望打开连接是阻塞的,但是,在这些连接上执行异步命令(通过dapper)的行为有所不同.那么,OpenAsync的做法有何不同?
编辑:
作为重现问题的请求代码(或者可能表现出差异).在执行大约180个并发异步命令时遇到运行此情况的Open()连接超时,使用OpenAsync()即使在超过300个并发命令时也不会遇到异常.您可以推动并发最终使其超时,但它肯定会更深入地执行并发命令.
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Dapper;
using Nito.AsyncEx;
namespace AsyncSqlConnectionTest
{
class Program
{
public static int concurrent_counter = 0;
public static int total_counter = 0;
static void Main(string[] args)
{
var listToConsume = Enumerable.Range(1, 10000).ToList();
Parallel.ForEach(listToConsume,
new ParallelOptions { },
value =>
{
try
{
Task.Run(() => AsyncContext.Run(async () =>
{
using (var conn = new SqlConnection("Data Source=.; Database=master; Trusted_Connection=True;"))
{
Interlocked.Increment(ref concurrent_counter);
Interlocked.Increment(ref total_counter);
await conn.OpenAsync();
var result = await conn.QueryAsync("select * from master..spt_values; waitfor delay '00:00:05'");
Console.WriteLine($"#{total_counter}, concurrent: {concurrent_counter}");
Interlocked.Decrement(ref concurrent_counter);
}
})).GetAwaiter().GetResult();
}
catch (Exception e)
{
Console.Write(e.ToString());
}
});
Console.ReadLine();
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑2:
这是一个只使用ADO.NET发现相同差异的测试.值得注意的是Dapper的执行速度要快得多,但这不是重点.同样,OpenAsync最终将获得超时,但是"更晚"并且永远不会,如果最大并行度为100(低于连接池大小).
using System;
using System.Data.SqlClient;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncSqlConnectionTest
{
class Program
{
public static int concurrent_counter = 0;
public static int total_counter = 0;
static void Main(string[] args)
{
var listToConsume = Enumerable.Range(1, 10000).ToList();
Parallel.ForEach(listToConsume,
new ParallelOptions { },
value =>
{
try
{
Task.Run(async () =>
{
using (var conn = new SqlConnection("Data Source=.; Database=master; Trusted_Connection=True;"))
{
Interlocked.Increment(ref concurrent_counter);
Interlocked.Increment(ref total_counter);
// this (no errors)
await conn.OpenAsync();
// vs. this (timeouts)
//conn.Open();
var cmd = new SqlCommand("select * from master..spt_values; waitfor delay '00:00:05'", conn);
using (var reader = await cmd.ExecuteReaderAsync())
{
while (await reader.ReadAsync()) { }
}
Console.WriteLine($"#{total_counter}, concurrent: {concurrent_counter}");
Interlocked.Decrement(ref concurrent_counter);
}
}).GetAwaiter().GetResult();
}
catch (Exception e)
{
Console.Write(e.ToString());
}
});
Console.ReadLine();
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 4
Open() 是一个同步进程,它会冻结 UI,而 OpenAsync() 是一个异步进程,它会在不冻结 UI 的情况下打开连接
public static async Task<SqlConnection> GetConnectionAsync()
{
var con = new SqlConnection(ConnectionString);
if (con.State != ConnectionState.Open)
await con.OpenAsync();
return con;
}
public async Task<int> ExecuteQueryAsync(SqlConnection con, string query)
{
if (con == null) con = await GetConnectionAsync();
var cmd = new SqlCommand(query, con);
return await cmd.ExecuteNonQueryAsync();
}
Run Code Online (Sandbox Code Playgroud)