【问题标题】:When to run an async function concurrently?何时同时运行异步函数?
【发布时间】:2012-09-18 17:29:43
【问题描述】:

异步等待功能使编写非阻塞代码变得优雅。但是,虽然是非阻塞的,但在异步函数中执行的工作仍然很重要。

在编写异步代码时,我发现编写遵循“一直到兔子洞”模式的代码是很自然的,可以这么说,调用树中的所有方法都标记为异步并且使用的 API 是异步的;但即使在非阻塞的情况下,执行的代码也会占用上下文线程相当多的时间。

您决定如何以及何时决定在异步之上同时运行一个支持异步的方法?是否应该在调用树中创建更高或更低的新任务?这种类型的“优化”是否有任何最佳实践?

【问题讨论】:

    标签: c# concurrency async-await


    【解决方案1】:

    几年来,我一直在生产中使用async。我推荐几个核心“最佳实践”:

    1. Don't block on async code。使用async“一直向下”。 (推论:比起async void,更喜欢async Task,除非你必须使用async void)。
    2. 在您的“库”方法中尽可能使用ConfigureAwait(false)

    您已经弄清楚了“async 一直向下”部分,并且您正处于 ConfigureAwait(false) 变得有用的地步。

    假设您有一个async 方法A 调用另一个async 方法BA 使用 B 的结果更新 UI,但 B 不依赖于 UI。所以我们有:

    async Task A()
    {
      var result = await B();
      myUIElement.Text = result;
    }
    
    async Task<string> B()
    {
      var rawString = await SomeOtherStuff();
      var result = DoProcessingOnRawString(rawString);
      return result;
    }
    

    在本例中,我将 B 称为“库”方法,因为它实际上并不需要在 UI 上下文中运行。现在,B确实在 UI 线程中运行,所以 DoProcessingOnRawString 会导致响应问题。

    所以,给B 中的每个await 添加一个ConfigureAwait(false)

    async Task<string> B()
    {
      var rawString = await SomeOtherStuff().ConfigureAwait(false);
      var result = DoProcessingOnRawString(rawString);
      return result;
    }
    

    现在,当Bawaiting SomeOtherStuff 之后恢复时(假设它确实必须await),它将在线程池线程而不是 UI 上下文上恢复。当B 完成时,即使它在线程池上运行,A 也会在 UI 上下文中恢复。

    您不能将ConfigureAwait(false) 添加到A,因为A 取决于UI 上下文。

    您还可以选择将任务显式排队到线程池 (await Task.Run(..)),如果您有特定的 CPU 密集型功能,您应该这样做。但是如果你的性能受到了“千刀万剐”的困扰,你可以使用ConfigureAwait(false)将大量的async“家务”卸载到线程池中。

    您可以找到我的intro post helpful(它涉及更多“为什么”),async FAQ 也有很多很好的参考。

    【讨论】:

    • 非常感谢,这是一个一流的答案,真的有助于澄清这个问题!
    • Async CTP,回溯……我想此时已经快 2 年了。我一直在为over a decade 做一般的异步编程,所以我是async 的早期采用者。
    【解决方案2】:

    异步等待does not actually use threads in the current .NET process-space。它是为“阻塞” IO 和网络操作而设计的,例如数据库调用、Web 请求、一些文件 IO。

    我无法理解 C# 对您所谓的兔子洞技术有什么优势。这样做只会使代码变得模糊,并且不必要地将潜在的高 CPU 代码与 IO 代码耦合。

    为了直接回答您的问题,我只会将 async-await 用于上述 IO/网络场景,就在您执行阻塞操作的地方,以及任何受 CPU 限制的情况我会使用线程技术来充分利用可用的 CPU 内核。无需将这两个问题混为一谈。

    【讨论】:

      猜你喜欢
      • 2015-09-19
      • 2023-02-05
      • 1970-01-01
      • 2021-09-23
      • 1970-01-01
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多