【问题标题】:Asynchronous call in C# using Oracle.DataAccess (ODAC)使用 Oracle.DataAccess (ODAC) 在 C# 中进行异步调用
【发布时间】:2014-12-30 01:32:00
【问题描述】:

我正在尝试对 Oracle 进行异步调用,但它是同步执行的。请看下面的代码,告诉我我做错了什么。

(我已安装 ODAC (ODTwithODAC1120320_32bit.zip) 并使用 Oracle.DataAccess.dll 程序集来调用 Oracle。在我使用已弃用的 System.Data.OracleClient 之前,结果相同。)

using System;
...
using System.Threading;
using System.Threading.Tasks;
using Oracle.DataAccess.Client;

namespace OracleTest
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    async private void button1_Click(object sender, EventArgs e)
    {
      OracleConnection connection = new OracleConnection("User Id=myuser;Password=mypwd;Data Source=mydb");
      connection.Open();  

      OracleCommand command = new OracleCommand("select count(col) from bigtable", connection);

      Task<Object> result = command.ExecuteScalarAsync();
      label1.Text = "BEFORE" + DateTime.Now.ToLocalTime() + " - ";
      label1.Text += await result;
      label1.Text += " - AFTER " + DateTime.Now.ToLocalTime();

      connection.Close(); 
      connection.Dispose(); 
    }
  }
}

dbms 需要几分钟才能获得计数。我期望的是: ExecuteScalarAsync 被调用,它给 Oracle 一个调用。在 BEFORE 时间之后立即写入 label1。然后我等待 Oracle 查询完成并获取结果。然后将 AFTER 时间写入 label1。所以之前和之后应该是不同的。但是,它们总是相同的时间(即查询返回结果的时间)。这是为什么呢?

我也试过

  CancellationToken cancellationToken = new CancellationToken();
  Task<Object> result = command.ExecuteScalarAsync(cancellationToken);

它并没有改变任何东西。 (这到底应该做什么?我不会简单地调用command.Cancel(); 而不是使用CancellationToken 吗?)

我的系统:Windows 8 Pro 64bit、Visual Studio Express 2013、Oracle Client 11g(32bit):OCI 11.2.0.01

【问题讨论】:

    标签: c# oracle asynchronous odac


    【解决方案1】:

    据我所知,Oracle 的提供者仍然没有实现异步方法。有人问过previously,我在 Oracle 的 OTN 或讨论论坛中找不到任何更新的内容。

    正如上一个问题的答案所说,Async 方法的默认实现是调用同步对应项,而不是在 Tasks 中运行它们(这实际上可能导致性能更差)。

    【讨论】:

    • 非常感谢。我没有看到另一个线程;也许是因为我只在寻找 ExecuteScalarAsync 。是的,这就解释了。遗憾的是,Oracle 只是将这些功能保留为未编写的 :-(
    【解决方案2】:

    如果你 look at the docs for ExecuteScalarAsync 它明确指出它“实现了 ExecuteScalar 的异步版本,但同步返回一个 Task,阻塞了调用线程。。因此它似乎正在按照它所说的那样做确实如此(阻塞调用线程)。

    要利用 ExecuteScalarAsync,您需要执行类似的操作

    using (object obj = await command.ExecuteScalarAsync())
    {
       //....
    }
    

    祝你好运。

    【讨论】:

    • 这不能解释也不能解决问题。任务的创建是同步的,命令的执行不应该是同步的。在using 中包装await 调用应该没有效果,甚至可能无法编译(object 没有实现IDisposable)。问题似乎是提供者实际上是同步执行调用,尽管文档说了什么。
    • @Bob Jarvis:感谢您的帮助。所以这意味着 ExecuteScalarAsync 和 ExecuteScalar 一样;它同步工作。它阻塞线程直到它完成,就像任何其他同步命令一样。他们或多或少地说:“我们实现了这个功能,因为继承迫使我们这样做,但我们只是实现错了”。那正确吗?顺便说一句:在这里 使用 有什么好处?我没有看到。 (而且它甚至不编译(错误:必须隐式转换为 IDisposable)。
    • @Panagiotis Kanavos:啊,谢谢你的评论。所以我似乎已经正确理解了这一点,并且该函数根本不是为了异步工作而编写的。
    • 请注意,此答案是指已弃用的 System.Data.Oracle 提供程序,而不是 ODAC。 ODAC 的文档可以在 Oracle 的站点上找到,而不是 MSDN。为了异步执行命令,可能需要特定的连接字符串参数等要求
    • @PanagiotisKanavos ODAC 甚至没有 Execute...Async 方法,所以我不知道 OP 的代码是如何编译的,除非他实际上仍在使用 System.Data。
    猜你喜欢
    • 1970-01-01
    • 2019-05-18
    • 2017-02-15
    • 2019-01-03
    • 1970-01-01
    • 1970-01-01
    • 2020-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多