【问题标题】:C# SQL connection OpenAsync is not asynchronousC# SQL 连接 OpenAsync 不是异步的
【发布时间】:2025-12-12 04:35:02
【问题描述】:

我正在尝试异步打开与 SQL 服务器的连接,以免占用 UI 线程。但是我发现在打开连接之前,对connection.OpenAsync() 的调用不会返回,与connection.Open() 完全一样。

这段代码重现了这个问题:

public static void Main(string[] args)
{
    System.Data.SqlClient.SqlConnectionStringBuilder builder = new System.Data.SqlClient.SqlConnectionStringBuilder();
    builder.UserID = "sa";
    builder.Password = "1234";
    builder.DataSource = "192.168.1.254\\SQLEXPRESS";
    builder.InitialCatalog = "MyDatabase";
    builder.PersistSecurityInfo = true;

    DbConnection connection = new System.Data.SqlClient.SqlConnection(builder.ConnectionString);

    Console.WriteLine("about to connect");

    Task connection_task = connection.OpenAsync();

    Console.WriteLine("started");

    while (!connection_task.IsCompleted && !connection_task.IsFaulted && !connection_task.IsCanceled)
    {
        Console.WriteLine("busy");
    }

    Console.WriteLine("done");
}

在这种情况下,192.168.1.254 不存在。消息about to connect 立即出现,但是在等待连接超时时没有任何反应,然后在连接超时后消息starteddone 同时出现。我希望消息started 会在消息about to connect 之后立即出现,然后消息done 会在连接超时后出现。

我猜我对返回的 Task 做错了,但Task-based Asynchronous Pattern 上的 Microsoft 页面肯定暗示我应该能够简单地调用 OpenAsync() 方法和返回的 Task将异步运行,而不是同步进行操作并占用调用线程直到 Task 完成。

【问题讨论】:

  • 我完全尝试了这段代码,它的行为符合预期,在“完成”之前我得到了“忙碌”的负载。这是 VS 2017 中针对 .NET 4.6.1 的新控制台应用程序。
  • 我的目标是 MonoDevelop 中的 .NET 4.5。我在 Windows 10 和 Linux 上遇到了相同的行为。
  • 我也得到了和亚当一样的结果,它打印了很多次“忙碌”,然后“完成”。
  • @Michael 好的,所以我们已经有所不同了。对我来说,这似乎是 Mono 中的一个错误,当它遇到可以注册某种等待的位置时,它不会产生任务。 async 不是并发的,它会同步运行,直到在向 IO 完成端口之类的东西注册后给予控制权。
  • @AndyJ 不是语法错误,ADO.NET 连接源自DbConnection

标签: c# multithreading asynchronous sqlconnection


【解决方案1】:

事实证明,这是 Mono 运行时中的一个错误,并且该代码在 Microsoft .NET 上运行良好。 MySQL .NET 库 (MySql.Data) 似乎也存在类似的错误,无论使用 Mono 还是 Microsoft .NET 运行时,它都会同步运行任务。

编辑:我找到了一个bug report 来解决 MySQL 的问题。

【讨论】:

  • 那个 bug 看起来不太可能被修复,伙计,它已经存在了一段时间 :-( 另一个 SO 问题:*.com/questions/21978629/…
  • @AdamHouldsworth 是的,看起来不会很快修复。不过没关系,我想我已经找到了适合我的特殊情况的解决方法。
【解决方案2】:

尝试将Asynchronous Processing=TrueAsync=True 属性添加到您的连接字符串中,

并在函数调用中添加等待,如下所示:await connection.OpenAsync();

希望对你有所帮助。

【讨论】:

  • 设置builder.AsynchronousProcessing = true 没有帮助。 await 使当前线程等待任务完成;我希望 不使用 使用await 我会得到预期的行为,当前线程继续而不等待任务完成。
  • 此设置在 .NET 4.5 及更高版本中是无操作的(根据 cmets 正在使用)。即使不是,它也只允许使用.BeginXXX 方法(即“旧”异步模型),否则会引发异常,并且对async/await 的使用应该没有影响.
  • await 不会让当前线程等待任务完成,而是让当前线程关闭并执行其他操作(除非任务开始时已经完成)。