web-dev-qa-db-ja.com

Oracle ManagedDriverはasync / waitを適切に使用できますか?

Async/wait.NET機能を使用してOracleクエリを作成しようとしました。結果セットはかなり大きく、戻ってくるまでに約5〜10秒かかります。 Window_LoadedはUIスレッドをハングさせています。基本的に、async/waitを使用してバックグラウンドでクエリを実行し、その結果でデータビューを更新したかったのです。

それで、これはOracleドライバの問題ですか、それともコードエラーですか?例えば。ここで何かが非同期ではなく同期的に行われていますか? OracleのWebサイトから入手できる最新のOracle.ManagedDataAccessを使用しています。

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

私はこれを試しましたが、それでもUIがデッドロックしています:

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

結局、デッドロックにならないようにメソッドをこのようなものに変更しました。 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();
}
25
user17753

いいえ。マネージドドライバーはasync/awaitをサポートしていません。

これらのメソッドは、インターフェイス定義に準拠するように実装する必要があるため、呼び出すことができますが、コードは実際には同期しています。必要に応じてTask.Runを使用できますが、同時に2つの呼び出しを行うことはできません(Oracleはそれらを同期すると脅します)。

19
Patrick Hofman

(これは、Oracle管理ドライバーに非同期を適切にサポートさせるための「解決策」であると思われるため、回答として残しておきます。)

Oracleのサイトで 古いスレッド (2010年から)を見つけました。OraclePMはそれをサポートしていないと言っています。 vote (Oracleアカウントが必要)でその機能を含めることができます。 5年後、残念ながら60票しか獲得できませんでした。

11
mason