使用 ADO.NET 异步调用 Oracle DB

问题描述 投票:0回答:3

我正在尝试使用 .NET Framework 4.5 中提供的异步和等待功能执行多个数据库调用。这是我第一次实现这个功能。

如果每个查询需要 7 秒,那么过去需要 35 秒(5 个查询 * 7 秒)。通过下面的实现,我预计它应该在接近 7-9 秒的时间内获取并填充 asp 页面中的控件。然而,它仍然需要 35 秒,这证明了我的同步行为。

有人可以帮我解决下面的异步实现哪里出了问题吗?

我很感激任何意见,几天来我一直在为此绞尽脑汁

    protected void Page_Load(object sender, System.EventArgs e)
    {
        RegisterAsyncTask(new PageAsyncTask(FillControlsAsync));
    }

    public async Task FillControlsAsync()
    {
         Task[] tasks = new Task[]{
         PopulateControlTask(query1, "controlID1"),
         PopulateControlTask(query2, "controlID2"),
         PopulateControlTask(query3, "controlID3"),
         PopulateControlTask(query4, "controlID4"),
         PopulateControlTask(query5, "controlID5")
        });

        await Task.WhenAll(tasks);
    }
    public async Task PopulateControlTask(string query, string control)
    {
       await Task.Run(() =>
           {
               DataSet ds;
               OracleCommand cmd;
               OracleDataAdapter da;
               try
               {
                   if (!Page.IsPostBack)
                   {
                       cmd = new OracleCommand(query, cn);
                       da = new OracleDataAdapter(cmd);
                       ds = new DataSet();
                       da.Fill(ds);
                       switch (control)
                       {
                           case "controlID1":
                                //some custom code for control 1
                                // like attaching the datasource to control.
                               break;
                           case "controlID2":
                               //some custom code for control 2
                               break;
                            case "controlID2":
                            //some custom code for control 3
                            break;
                            case "controlID3":
                            //some custom code for control 4
                            break;
                            case "controlID4":
                            //some custom code for control 5
                            break;
                    }
                }
            }
            catch(Exception e)
            {
                 //some error handling here
            }
        });
    }
c# asp.net webforms ado.net async-await
3个回答
5
投票

async
await
用于异步代码。通常,如果您有一个可扩展的数据库,您可以使数据库调用异步,从而扩展您的服务器。请注意,
async
在 ASP.NET 上的主要好处是可扩展性,而不是响应时间。

但是,正如其他人指出的那样,Oracle 不支持异步代码。

但这并不重要,因为您发布的代码

实际上并不是异步的!这就是我所说的“假异步”,因为它只是使用 Task.Run

 将同步工作推送到后台线程,而不是使用自然异步 API。 (但正如已经指出的,在这种情况下(即 Oracle),您没有任何自然异步 API 可以使用)。

所以,你最终得到的是

并行,而不是异步。特别是,代码将自身分布在 5 个线程池线程上来完成其工作。

现在,您需要做的第一件事是问自己是否“真的”想要服务器上的并行性。您的请求将占用 5 个线程,而不是 1 个(或 0 个)。这会极大地影响 Web 服务器的可扩展性(以一种不好的方式)。另外,请考虑后端的功能。如果它是一台服务器,并且这些查询全部命中单个硬盘驱动器上的单个数据库,那么并行化其中 5 个查询实际上会产生任何好处,还是实际上会因为磁盘争用而同样糟糕(如果不是更糟的话)? (您应该能够创建一个快速控制台应用程序来测试您的数据库在空闲和负载时如何响应串行与并行请求)。

我发现绝大多数时候,答案是“不,我不想让整个数据库服务器因为这个请求而崩溃”——换句话说,避免服务器上的并行性。

但是,如果您权衡了各种选项并决定是的,您的情况是在 ASP.NET 上适用并行性的罕见情况之一,

那么

您应该问您在此处发布的问题:为什么这些顺序运行

而不是 并发?(旁注:这里是 顺序 vs 并发,而不是同步 vs 异步 答案:我不知道。

但我有一个猜测:如果数据库连接(代码片段中的

cn

)是共享的,那么数据库连接本身很可能一次仅限于一个查询。其他数据库连接系统也有类似的限制。我尝试的第一件事是为每个查询提供自己的连接。

也就是说,
如果

您想要并行化您的 Web 服务器。这是一个

“如果”。

跟进有关Oracle异步实现的其他答案(没有足够的声誉来评论),Oracle的异步方法并不是真正的异步,只是在幕后调用同步方法,因此调用它们的性能比同步方法更差。

2
投票
您可以观看

https://github.com/oracle/dotnet-db-samples/issues/144

,看看他们是否会提供真正的异步实现。截至 2022 年第一季度,Oracle .NET 团队表示可能会在 2022 年第四季度。

ODP.NET Core 和托管 ODP.NET 23.2 开发版本(包的预览版本)现在完全支持异步等待:

0
投票
© www.soinside.com 2019 - 2024. All rights reserved.