Oracle 托管驱动程序可以正确使用 async/await 吗?
Posted
技术标签:
【中文标题】Oracle 托管驱动程序可以正确使用 async/await 吗?【英文标题】:Can the Oracle managed driver use async/await properly? 【发布时间】:2015-05-15 00:26:08 【问题描述】:我试图使用 async/await .NET 功能进行 Oracle 查询。结果集非常大,大约需要 5-10 秒才能返回。 Window_Loaded
正在挂起 UI 线程,本质上我想使用 async/wait 在后台进行查询,然后用结果更新数据视图。
那么这是 Oracle 驱动程序问题还是代码错误?例如。这里的事情是同步而不是异步完成的吗?我正在使用最新的Oracle.ManagedDataAccess
,我可以从 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();
我试过了,它仍然阻塞 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 托管库同步实现了 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();
【问题讨论】:
您可以尝试获取代码 dt.Load(reader);进入一个任务,比如 await Task.Run(() => dt.Load(reader));此外,代码对我来说看起来不错。 仅供参考,我向 Oracle 发送了关于异步支持的电子邮件并收到了回复:“我没有任何关于 ODP.NET 托管驱动程序何时需要异步的新信息。” 他们在 7 天前发布了新版本 18.3(最后一个是 12.2)。 nuget.org/packages/Oracle.ManagedDataAccess/18.3.0 也许这个新的真的是异步的。谁能确认一下? @lmcarreiro 当然不是。甲骨文没有计划实施这一点。解决这个问题的唯一方法是转移到……嗯,几乎可以说是任何其他数据库,因为其他数据库似乎没有 Oracle 的问题。 我编辑了问题中的文字,将“死锁”替换为“块”,我认为更准确。死锁是永远阻塞的东西,而不仅仅是几秒钟。 【参考方案1】:(我将此作为答案,因为它似乎是让 Oracle 托管驱动程序正确支持异步的“解决方案”。)
我在 Oracle 的网站上找到了 old thread(从 2010 年开始),Oracle PM 说他们不支持它。您可以vote(必须有 Oracle 帐户)来包含该功能。遗憾的是,5 年后它只获得了 60 票。
【讨论】:
现在是 2019 年,一切都没有改变。 来自 Oracle .NET 团队:“还没有异步支持。这也是我们正在开展的一个项目。”我们仍然有希望使用 Oracle。 twitter.com/OracleDOTNET/status/1227374014177280000 @DoubleJ 他们说他们也会在 5 年前研究它。你真的信任甲骨文吗? 近 6 年过去了,我们仍在等待。 gg 甲骨文。 现在是 2021 年,一切都没有改变。尚无异步支持。【参考方案2】:没有。托管驱动程序不支持async
/ await
。
您可以调用这些方法,因为它们必须按照接口定义来实现,但代码实际上是同步的。如果你愿意,你可以使用Task.Run
,但你不能同时有两个调用(Oracle 会威胁它们同步)。
【讨论】:
谢谢,在尝试获取async
/await
时,某些标记为async
的方法实际上是同步实现的,这非常令人困惑。
@user17753 不仅令人困惑,it's frustrating。
微软没有实现驱动。甲骨文可以。 @tacos_tacos_tacos
虽然情况并非如此,但 Oracle 甚至可能没有意识到他们应该重写从 DbConnection
、DbCommand
继承的异步方法的实现......这个实现只是依赖于同步方法。 ODAC 存在于 ADO.Net 类型上的那些异步方法之前。它们被添加到 ADO.Net 类型上而不太可能是抽象的,因为否则这对所有提供者来说都是一个重大变化。至于在默认实现引发异常或同步回退之间进行选择,我个人更喜欢后者。这是微软的选择。
@Frédéric 他们确实知道,因为几年前我与他们负责 .NET 驱动程序的人交谈过。我宁愿他们抛出 NotImplementedException 而不是错误地让你相信他们有异步支持。以上是关于Oracle 托管驱动程序可以正确使用 async/await 吗?的主要内容,如果未能解决你的问题,请参考以下文章
Oracle官方非托管Odac驱动与Oracle官方托管odac驱动
OwinCommunicationListener 中托管的 Async Web Api 中的 Fire and Forget 方法
如何正确理解.NET 4.5和C#5.0中的async/await异步编程模式