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();
}
いいえ。マネージドドライバーはasync
/await
をサポートしていません。
これらのメソッドは、インターフェイス定義に準拠するように実装する必要があるため、呼び出すことができますが、コードは実際には同期しています。必要に応じてTask.Run
を使用できますが、同時に2つの呼び出しを行うことはできません(Oracleはそれらを同期すると脅します)。