Oracle托管驱动程序可以正确使用异步/等待吗?

use*_*753 22 .net c# oracle async-await odp.net-managed

我试图使用async/wait .NET功能进行Oracle查询.结果集非常大,需要大约5-10秒才能恢复.Window_Loaded挂起了UI线程,本质上我想使用async/wait在后台进行查询,然后使用结果更新数据视图.

这是Oracle驱动程序问题还是代码错误?例如,这是同步而不是异步完成的事情吗?我正在使用Oracle.ManagedDataAccessOracle可以从Oracle网站获得的最新信息.

async Task<DataTable> AccessOracleAsync()
{
    DataTable dt;
    using(OracleConnection conn = new OracleConnection(ConfigurationManager.ConnectionStrings["connStr"].ConnectionString))
    using (OracleCommand cmd = new OracleCommand(@"SELECT * FROM myTbl", conn))
    {
        await conn.OpenAsync();
        using (var reader = await cmd.ExecuteReaderAsync())
        {
            dt = new DataTable();
            dt.Load(reader);                        
        }
    }

    return dt;
}

private async void Window_Loaded(object sender, RoutedEventArgs e)
{
    await AccessOracleAsync();
}
Run Code Online (Sandbox Code Playgroud)

我试过这个,它仍然在用户界面陷入僵局:

async Task<DataView> AccessOracleAsync()
{
        DataTable dt;
        using (OracleConnection conn = new OracleConnection(ConfigurationManager.ConnectionStrings["connStr"].ConnectionString))
        using (OracleCommand cmd = new OracleCommand(@"SELECT * FROM myTbl", conn))
        {
            await conn.OpenAsync().ConfigureAwait(false);
            using (DbDataReader reader = await cmd.ExecuteReaderAsync().ConfigureAwait(false))
            {
                dt = new DataTable();
                await Task.Run(() => dt.Load(reader)).ConfigureAwait(false);
            }

        }
        return dt.AsDataView();
}

private async void Window_Loaded(object sender, RoutedEventArgs e)
{
    Data1.ItemsSource = await AccessOracleAsync();
}
Run Code Online (Sandbox Code Playgroud)

所以最后,我将方法更改为这样的方法,使其不会死锁.看来我有正确的想法,只是Oracle Managed库同步实现了Async方法(只是为了符合接口).

private async Task<DataView> AccessOracleAsync()
{
        DataTable dt = new DataTable();
        using (OracleConnection conn = new OracleConnection(ConfigurationManager.ConnectionStrings["connStr"].ConnectionString))
        using (OracleCommand cmd = new OracleCommand(@"SELECT * myTbl", conn))
        {
            await Task.Run(() =>
                {
                    conn.Open();
                    using (DbDataReader reader = cmd.ExecuteReader())
                    {
                        dt.Load(reader);
                    }
                }).ConfigureAwait(false);

        }
        return dt.AsDataView();
}
Run Code Online (Sandbox Code Playgroud)

Pat*_*man 16

不.托管驱动程序不支持async/ await.

您可以调用这些方法,因为它们必须实现以符合接口定义,但代码实际上是同步的.您可以Task.Run根据需要使用,但不能同时进行两次调用(Oracle会威胁它们同步).

  • @ user17753不仅令人困惑,[令人沮丧](http://stackoverflow.com/questions/28544557/async-io-intensive-code-is-running-slower-than-non-async-why/29034733#29034733 ). (8认同)
  • 谢谢,当尝试拾取`async` /`await`时,对于一些标记为`async`的方法实际上是同步实现的,这是非常令人困惑的. (5认同)
  • @Frédéric他们知道,因为几年前我和他们负责.NET驱动程序的人谈过了.我宁愿他们抛出NotImplementedException而不是错误地让你相信他们有异步支持. (5认同)
  • Microsoft未实现该驱动程序.甲骨文做的.@tacos_tacos_tacos (4认同)
  • 尽管情况并非如此,Oracle 甚至可能不知道他们应该覆盖从`DbConnection`、`DbCommand` 继承的异步方法的实现,...这个实现只是依赖于同步方法。ODAC 在 ADO.Net 类型上的那些异步方法之前就已经存在。它们很可能被添加到 ADO.Net 类型而不是抽象的,否则对于所有提供者来说这将是一个重大变化。至于在默认实现抛出异常或同步回退之间进行选择,我个人更喜欢后者。那是微软的选择。 (2认同)

mas*_*son 10

(我将此作为答案,因为它似乎是让Oracle托管驱动程序正确支持异步的"解决方案".)

我在甲骨文的网站上发现了一个旧的线程(从2010年开始),Oracle PM表示他们不支持它.您可以投票(必须拥有Oracle帐户)以包含该功能.5年后,遗憾的是只获得了60票.

  • @DoubleJ 他们五年前就说过他们会致力于此。您真的信任甲骨文吗? (4认同)
  • 现在已经是 2019 年了,一切都没有改变。 (3认同)
  • 现在是 2022 年,没有异步支持,没有投票……Oracle 离开了我们,所以人们可能已经离开了 Oracle。 (3认同)
  • 我会定期重温此线程以自娱自乐。我们永远与 Oracle 联姻。我不久前发现了这一点,他们最初说是 2022 年第四季度,但已经被推迟到 2023 年。有一天 Oracle,有一天...... https://github.com/oracle/dotnet-db-samples/issues/144 (2认同)

Dou*_*leJ 7

经过 10 多年的努力,Oracle 终于发布了支持 async/await 的托管驱动程序的开发(测试版)版本。

Github问题:
https://github.com/oracle/dotnet-db-samples/issues/144#issuecomment-1656674986

Oracle 说明:
https://docs.oracle.com/en/database/oracle/oracle-database/23/odpnt/featAsyncPipelined.html#GUID-27CA3823-92BA-489A-9356-9EAA7B86A4FE

.NET Core 的 Nuget 包:
https://www.nuget.org/packages/Oracle.ManagedDataAccess.Core/23.2.0-dev

如果您想安装它,您需要在 Visual Studio 中启用预发布,因为它仅处于开发阶段(测试版)。