Oracle客户端 vs 基于任务的异步模式(async/await)

9
我想用async/await的方式编写一堆查询Oracle数据库的方法。由于ODP.NET似乎既不支持可等待的*Async方法,也不支持Begin/EndOperationName对,那么我该如何手动实现呢?
到目前为止,我看到的所有I/O密集型异步方法的示例都只调用.NET库中的其他异步方法,但没有解释内部是如何进行上下文切换的。文档指出,在这些情况下不会使用单独的线程,并且多线程开销显然仅在CPU密集型操作中值得。因此,我想Task.Run()不是一个选项,或者我错了吗?

ODP.NET有任何可以适应的异步模式吗?您可能想阅读http://blogs.msdn.com/b/pfxteam/archive/2012/03/24/10287244.aspx - Jon Skeet
除了ODP.NET之外,是否有其他选择(商业ADO.NET提供程序)? - Yahia
@metalheart 好的,那唯一的选择就是使用连接池,并构建您的任务以从该池请求它们所需的连接... 这样,您应该能够使用 Task.Run... 尽管不像“真正的异步”那么高效,但这应该会带来一些好处... - Yahia
2
@metalheart 我了解到...就像我所说的一样: 你不会像使用真正的异步实现那样达到相同的效果,但是这比“纯同步”好... 我知道的唯一支持实际异步的Oracle ADO.NET提供程序都是商业性质的,而你已经排除了它们... 所以很遗憾,我没有太多可以帮到你的东西! - Yahia
假设您正在开发服务器应用程序:您应该熟悉异步IO何时有帮助以及何时没有。 https://dev59.com/ml8f5IYBdhLWcg3wD_Av#25087273 https://dev59.com/eGcs5IYBdhLWcg3wgkMQ#12796711 (您在评论中对“更好的扩展性”做出了一些模糊的陈述。这就是我推荐阅读材料的原因。如果您在客户端使用异步IO,Oracle不会以任何方式获得更好的扩展性。) - usr
显示剩余2条评论
3个回答

1
只要我了解,Oracle ODP是一个异步库的同步包装器。我发现这篇文章,因为我也在想同样的问题:引入Oracle ODP调用的异步模式是否会提高性能?(我正在使用WCF在IIS NET TCP上)。但是,正如已经说过的那样,只要引入异步模式是通过创建一个新任务并且调用线程已经来自线程池,就无法做出改进,它只会成为一种负担。

-1

你可以随时使用 Task.Factory.StartNewTaskCreationOptions.LongRunning,这样 .NET 就会创建一个新线程而不是使用线程池线程。以下是手动异步代码,您可以将其应用于您的操作。

private static void ManualAsyncOperation()
        {

            Task<string> task = Task.Factory.StartNew(() =>
                {
                    Console.WriteLine("Accessing database .....");
                    //Mimic the DB operation 
                    Thread.Sleep(1000);

                    return "Hello wolrd";
                },TaskCreationOptions.LongRunning);

            var awaiter =task.GetAwaiter();
            awaiter.OnCompleted(() =>
                {
                    try
                    {
                        var result = awaiter.GetResult();

                        Console.WriteLine("Result: {0}", result);
                    }
                    catch (Exception exception)
                    {

                        Console.WriteLine("Exception: {0}",exception);
                    }
                });
            Console.WriteLine("Continuing on the main thread and waiting for the result ....");
            Console.WriteLine();

            Console.ReadLine();

        }

1
我很好奇是否可以在不使用线程的情况下实现异步行为...也许我的解决方案在调用许多数据库操作时无法很好地扩展。 - metalheart
1
你为什么要使用GetAwaiter()而不是普通的继续(或await)? - Reed Copsey
1
@ReedCopsey,就这个具体问题而言,作者问道:“由于ODP.NET似乎既不支持可等待的*Async方法,也不支持Begin/EndOperationName对,我有哪些选项可以手动实现?”因此,我使用了GetAwaiter()。抱歉回复晚了。 - Toan Nguyen
1
@ToanNguyen 你应该在从Task.Factory.StartNew创建的任务上使用ContinueWith - 在这种情况下没有理由获取awaiter... 这是一个奇怪的选择来创建一个继续。 - Reed Copsey

-1

我正在使用这个

public static class TaskHelper
{
    public async static Task<T> AsAsync<T>(Func<T> function, TaskCreationOptions taskCreationOptions = TaskCreationOptions.None)
    {
        return await Task.Factory.StartNew(function, taskCreationOptions);
    }

    public async static Task AsAsync(Action action, TaskCreationOptions taskCreationOptions = TaskCreationOptions.None)
    {
        await Task.Factory.StartNew(action, taskCreationOptions);
    }
}

任何同步函数都可以转换为异步函数,你可以使用await来等待它。

1
这会降低吞吐量。不适合服务器端使用。 - usr
当然,如果您不需要异步操作,就必须避免使用它们。但是,如果您想要UI或IIS的非阻塞行为,就必须像这样做。但是,就像我说的那样,您必须决定在这里是否需要异步操作。 - Demetrius Axenowski
在IIS中,您不需要非阻塞行为。对于UI来说,这是有用的。 - usr
无法。IIS 请求使用标准线程池。你归还一个线程并立即拉出另一个线程。关于请求的并行执行,IIS 和 ASP.NET 没有实际相关的限制(不易提高)。 - usr
这是一个非常适合异步处理的工作负载:1000毫秒的延迟 :) 如果将延迟放在线程池上,它是无法工作的(在这种情况下不会观察到加速)。它通过使用无需线程的Task.Delay来实现。 - usr
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接