【问题标题】:Async odbc seems to be synchronous异步 odbc 似乎是同步的
【发布时间】:2017-10-30 08:50:24
【问题描述】:

我正在尝试执行异步数据库查询,但是当我测试我的代码时,它似乎是同步的。我已将问题隔离到我的查询功能。无法弄清楚我做错了什么,我对 aync/await 功能很陌生,所以我可能做了一些愚蠢的事情:)

这是失败的代码:(我正在使用本地安装的 postgresql)

    public static void Main()
    {
        Task.Run(async () => await MainAsync()).GetAwaiter().GetResult();
    }

    public static async Task MainAsync()
    {
        await TestDbSleep(5);
    }

    public static async Task TestDbSleep(int seconds)
    {
        Console.WriteLine("{0} Starting tasks!", DateTime.Now.ToString("HH:mm:ss"));
        var tasks = new[] { DbSleep(5, "first"), DbSleep(seconds, "second"), DbSleep(seconds, "third") };
        Console.WriteLine("All tasks started!");
        await Task.WhenAll(tasks);
        Console.WriteLine("{0} All tasks done!", DateTime.Now.ToString("HH:mm:ss"));
    }

    public static async Task<DbDataReader> DbSleep(int seconds, string name)
    {
        Console.WriteLine("Starting {0}!", name);
        var result = await Query("SELECT * FROM pg_sleep(?)", new OdbcParameter("seconds", seconds));
        Console.WriteLine("{0} done!", name);
        return result;
    }

    public static async Task<DbDataReader> Query(string sql, params OdbcParameter[] parameters)
    {   
        using (var dbConn = new OdbcConnection(ConfigurationManager.ConnectionStrings["MainConnectionString"].ConnectionString))
        {
            await dbConn.OpenAsync();
            var command = new OdbcCommand(sql, dbConn);
            if (parameters != null)
            {
                foreach (var parameter in parameters)
                {
                    command.Parameters.Add(parameter);
                }
            }
            return await command.ExecuteReaderAsync();
        }
    }

当我运行这段代码时,我得到了这个输出:

09:29:20 Starting tasks!
Starting first!
first done!
Starting second!
second done!
Starting third!
third done!
All tasks started!
09:29:36 All tasks done!

为什么第二个和第三个任务不直接启动呢?为什么需要 16 秒?

我尝试用 await Task.Delay(seconds * 1000) 替换对我的 Query 函数的调用,当我这样做时,代码会像这样异步执行:

09:29:15 Starting tasks!
Starting first!
Starting second!
Starting third!
All tasks started!
third done!
second done!
first done!
09:29:20 All tasks done!

【问题讨论】:

  • @Fildor:我不认为这是一个特别有用的评论。 DbSleep 似乎是适当异步的,如果 Query 本身是异步的 - 如果 ODBC 部分是适当异步的,那就是这样。如果您有更多关于您期望该行为的原因的详细信息,请提供该详细信息。在我看来,OP 已经非常清楚地描述了问题和代码......我希望DbSleep 几乎立即返回任务,而不是(似乎是这样)仅在完成后才这样做。
  • 不,它不会,但如果我等待 Task.Delay(seconds * 5) 而不是 await Query("SELECT...") 我不明白为什么
  • @Fildor:为什么要同步执行?它所做的只是多次调用DbSleep。这些方法调用中的每一个都会产生一个任务(并且应该快速产生它)——它不会等待它。等待稍后发生:await Task.WhenAll(tasks);
  • 会不会是在“同步”方法中创建 OdbcConnection ?您是否尝试将打开的连接传递给查询,而不是每个都打开/关闭自己的连接?
  • 经过更多测试后,似乎对 OdbcConnection.OpenAsync 和 OdbcCommand.ExecuteReaderAsync 的调用是同步执行的。在 OdbcConnection.OpenAsync 的文档中,它说“默认实现调用同步 Open 调用并返回一个已完成的任务”,这似乎证实了这一点。

标签: c# asynchronous ado.net async-await


【解决方案1】:

问题是我认为 OdbcConnection.OpenAsync() 和 OdbcCommand.ExecuteReaderAsync() 实际上是异步方法,但它们不是。

我在 msdn 上阅读了如何使用 SqlConnection 和 SqlCommand 异步,但我可以将其应用于 OdbcConnection/OdbcCommand,结果证明是错误的。

我已经通过使用 Npgsql:s NpgsqlConnection、NpgsqlCommand 和 NpgsqlParameter 类而不是 .NETs Odbc 类来实现它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多