SqlConnection.Open与SqlConnection.OpenAsync - 两者之间有什么不同?

时间:2016-11-17 18:49:59

标签: c# asynchronous ado.net

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

除了明显的异步行为之外,同步代码中的SqlConnection.Open调用和异步代码中的等待SqlConnection.OpenAsync调用之间的区别是什么?底层连接是否与数据库异步?

OpenAsync的文档是lite,https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.openasync%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

  

Open的异步版本,用于打开数据库连接   使用ConnectionString指定的设置。这种方法   用VB调用虚方法OpenAsync   CancellationToken.None。(继承自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();
        }
    }
}

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

0 个答案:

没有答案