ExecuteScalarAsync 挂起,但 ExecuteScalar 立即返回

m3z*_*m3z 6 c# sql-server async-await

所以我遇到了一个让我困惑的小问题,我一直无法找到一个很好的解释 - 我想我可能以某种方式错误地使用了 async/await 功能,但我真的不知道是什么我做错了。

所以我有一些 sql 代码来查询我的数据库并返回一个值。因此,我使用 ExecuteScalarAsync 将该值输出到 C# 中。

代码如下:

public void CheckOldTransactionsSync()
{
    CheckOldTransactions().Wait();
}

public async Task CheckOldTransactions()
{
    DateTimeOffset beforeThis = DateTime.UtcNow.Subtract(TimeSpan.FromHours(6));

    using (SqlConnection connection = new SqlConnection(SqlConnectionString))
    {
        await connection.OpenAsync(cts.Token);
        using (SqlCommand command = new SqlCommand(@"SELECT TOP 1 1 AS value FROM SyncLog WHERE [TimeStamp] < @BeforeThis;", connection))
        {
            command.Parameters.Add("@BeforeThis", System.Data.SqlDbType.DateTimeOffset, 7);

            command.Prepare();
            command.Parameters["@BeforeThis"].Value = beforeThis;

            Int32 oldTransactions = (Int32)await command.ExecuteScalarAsync(cts.Token);

            // do stuff with oldTransactions
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,在我的代码中的其他地方,创建了名为 cts 的 CancellationTokenSource,并使用 CancelAfter 方法将其设置为在 2 分钟后过期。

现在,我已经使用调试器单步调试了这段代码,并且毫无问题地到达了等待对 ExecuteScalarAsync 的调用的行。然而,我似乎在执行该行时遇到两个问题,一是它似乎没有返回,二是它忽略我的取消令牌,并且在我的两分钟取消令牌过期后仍在运行一段时间。

现在我已经在 Sql Studio 中运行 sql 查询,它返回得非常快 - 此时表只有大约 4000 行。

我现在已经解决了这个问题,将该行更改为:

Int32 oldTransactions = (Int32) command.ExecuteScalar();
Run Code Online (Sandbox Code Playgroud)

几乎立即返回。

这是我更改的唯一一行代码,我将其改回来只是为了确保发生同样的问题。所以我的问题是,我的异步调用做错了什么?

usr*_*usr 5

你正在呼唤Wait

这是典型的 ASP.NET 死锁。不要阻塞,或者使用同步IO。