SqlConnection.打开vs SqlConnection.OpenAsync -两者之间的区别除了显而易见之外

本文关键字:SqlConnection 显而易见 区别 打开 vs OpenAsync 两者之间 | 更新日期: 2023-09-27 18:18:23

Edit:这归结为为什么在异步代码中更改SqlConnection.Open()以等待SqlConnection.OpenAsync()会导致强烈不同的行为。

SqlConnection和SqlConnection的区别是什么?在同步代码中打开调用并等待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指定的设置。这个方法调用虚拟方法OpenAsync withCancellationToken.None。(继承自DbConnection.)

我发现有趣的是,以前的连接字符串需要async=true,而在。net 4.5+中不再需要。连接的行为不同吗?

https://msdn.microsoft.com/en-us/library/hh211418 (v = vs.110) . aspx

从。net Framework 4.5开始,这些方法不再需要异步处理=连接字符串中的true。

当我碰巧使用同步SqlConnection。在异步应用程序中打开并大量加载它,我发现它的性能非常差,连接池运行得很早。我期望打开连接是阻塞的,然而,在这些连接上执行异步命令(通过dapper)的行为不同。那么,OpenAsync做什么不同?

编辑:

按照请求的代码重现问题(或者可能显示差异)。使用Open()运行这种情况,在大约180个并发异步命令执行时遇到连接超时,使用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();
        }
    }
}

编辑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();
        }
    }
}

SqlConnection.打开vs SqlConnection.OpenAsync -两者之间的区别除了显而易见之外

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();   
}