【问题标题】:Is there any purpose to multiple awaits in a single async method在单个异步方法中进行多个等待是否有任何目的
【发布时间】:2018-03-05 19:34:40
【问题描述】:

如果你有异步函数:

public async Task DoWork()
{
    await DoSomeWorkAsync();
    await DoSomeMoreWorkAsync();
}

现在第一个 await 可以防止方法阻塞调用上下文,所以很有用。

但在DoSomeWorkAsync 完成后,该方法无论如何都会在不同的上下文中运行,因为在编译器中它已被转换为Task.ContinueWith(await DoSomeMoreWorkAsync()) 之类的东西。

那么他们等待DoSomeMoreWorkAsync/异步运行它有什么目的吗?有什么缺点吗?如果存在,我应该使用DoSomeMoreWorkAsync 的非异步版本吗?

即。这是否有任何不利之处:

public async Task DoWork()
{
    await DoSomeWorkAsync();
    DoSomeMoreWork();
}

编辑:这与Multiple Awaits in a single method 不是同一个问题。那问会发生什么。我在问这样做有什么好处。

【问题讨论】:

  • @HimBromBeere:这与现有问题不同。那问会发生什么。我在问这种情况有什么好处。我在问这个问题之前看过这个问题。
  • 嗯,重点显然是您的 asnyc 方法应该执行 多个 步骤。对于您的呼叫成员,这些步骤是隐藏的,因为它对您的方法的内部一无所知。然而,对于后者,它只是一个接一个的流程流程。因此,对于 asnyc 方法,您有一些子任务应该同步执行,这意味着:首先执行DoSometWork,然后在完成时执行DoSomeMoreWork。只有后者完成了,asny方法返回的整个任务才完成。

标签: c# asynchronous async-await


【解决方案1】:

您似乎认为避免阻塞调用者是异步方法的唯一目的,事实并非如此。异步方法通常是异步的,因为在某些时候它们会执行异步 IO,例如处理文件、数据库、Web 请求等(或调用其他异步方法来执行此操作)。

当真正的异步 IO 正在进行时,您的应用程序中没有线程忙于等待它完成(嗯,有线程,但它是一个用于整个应用程序的线程,而不是针对每个特定 IO 任务的线程)。

这意味着即使 IF await DoSomeMoreWorkAsync 在某个线程池线程上执行 - 当它到达异步 IO 时 - 该线程池线程将被释放并可以用于更有用的工作。

另一方面,如果您将使用同步版本 (DoSomeMoreWork) - 它将在整个持续时间内阻塞当前线程池线程,包括 IO,因此该线程将无法用于有用的工作。

在大量使用线程的应用程序(例如 Web 应用程序)中,尽可能释放线程可能非常重要。

除上述外,此声明

但在 DoSomeWorkAsync 完成后,该方法仍然在运行 在不同的环境中

并不总是正确的。例如在 UI 应用程序中,如果您从 UI 线程调用 DoWork,则继续 (await DoSomeMoreWorkAsync()) 也会在 UI 线程上执行。这意味着如果您将其替换为同步版本 - UI 线程将在此期间冻结。

【讨论】:

  • 谢谢。这正是我要问的
【解决方案2】:

那么等待DoSomeMoreWorkAsync有什么目的吗?

好吧,如果它是异步的,那么您绝对希望等待它,这样您的 DoWork 方法就不会在“更多工作”完成之前完成。如果它是异步的,并且您没有等待它,那么它本质上会触发并忘记您想要的很少

那么异步运行它有什么目的吗?

这取决于功能。您不要使方法异步,因为您想调用它们是异步的。方法是异步的,因为它们执行异步任务。

如果该方法正在执行纯粹的 CPU 绑定工作,无论如何都不会异步运行,那么就没有理由让它异步,不。实际上,让它保持同步以清楚地与调用者沟通没有异步过程正在进行。

但是,如果它可以从异步中受益,例如因为它执行异步网络或 I/O 调用,所以它可能应该是异步的。然后你也应该等待它。

有什么缺点吗?

总是有缺点的。运行异步代码比运行同步代码更昂贵,因为会产生和调用大量开销(幸运的是,我们在编写异步代码时不必处理这些开销)。但是在查看真正的异步代码可以给您带来的优势时,这种开销并不重要。

所以你真的不应该用它来决定是否做一些异步的东西。想一想这个方法做了什么以及它是如何做的,然后决定这个过程是同步的还是异步的。

【讨论】:

  • 许多 IO 库同时提供其调用的异步和非异步版本。所以考虑到这个方法无论如何都是异步运行的,我应该使用非异步版本来避免开销吗?
  • 同样,这取决于函数在做什么,而不是你想如何调用它。如果它是一个可以从异步中受益的过程,那么你最好让它异步。提供异步和同步调用的库通常只是阻塞异步调用以使其同步。
猜你喜欢
  • 1970-01-01
  • 2021-10-14
  • 1970-01-01
  • 1970-01-01
  • 2013-12-15
  • 1970-01-01
  • 1970-01-01
  • 2016-03-16
相关资源
最近更新 更多