async 和 await 如何替代现有方法?

How do async and await replace existing approaches?

来自https://msdn.microsoft.com/en-us/library/mt674882.aspx#Threads

The async-based approach to asynchronous programming is preferable to existing approaches in almost every case. In particular, this approach is better than BackgroundWorker for IO-bound operations because the code is simpler and you don't have to guard against race conditions. In combination with Task.Run, async programming is better than BackgroundWorker for CPU-bound operations because async programming separates the coordination details of running your code from the work that Task.Run transfers to the threadpool.

在我看来,一系列 async 函数最终必须以等待程序控制之外的事情发生而结束。一些 Internet 下载或用户输入或其他内容。

如果您的程序必须执行一些冗长的计算,情况会怎样?它必须在一个本身不使用 await 的方法中,因为当它自己完成所有工作时没有什么可等待的。如果不使用 await 则控制不会 return 返回到调用函数,对吗?如果是这样,那么它肯定根本就不是异步的。

看来 BackgroundWorker 很适合冗长的计算:https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx#Examples

有什么方法可以使用 async/await 吗?

关键在这里:

In combination with Task.Run, async programming is better than BackgroundWorker for CPU-bound operations because async programming separates the coordination details of running your code from the work that Task.Run transfers to the threadpool.

对于CPU-bound工作(或IO-bound,没关系),Task.Run会将您的代码运行放在线程池的单独线程中,因此当前代码可以 await 它,因为它 运行ning 在不同的线程上。从第二个线程的角度来看,工作是同步的,但是从第一个线程的角度,工作是异步的。

第二件事是协调上下文。我没用过BackgroundWorker,但根据我对文字的理解,它需要你手动检查工作是否完成,然后检索结果,或者传播异常,等等。在 async/await 方法中,所有这些都为您涵盖。

总而言之,与 BackgroundWorker 方式相比,async/await 方式似乎是一种更友好可读的处理方式。

编辑:

您不能在 non-awaitable 方法上使用 await。 CPU-bound 任务永远不可能是真正异步的,因为需要计算一些东西,为此需要一个线程。要么当前线程会做计算(阻塞),要么交给另一个后台线程,所以当前线程是非阻塞和异步的。

如果您熟悉 Node.js,您会注意到处理 CPU-bound 任务非常棘手,并且经常需要重构代码。

但是,作为用户,无论您等待的方法是真正的异步方法还是使用另一个线程,您当前的线程都是异步的。

It seems to me that a chain of async functions must eventually end in waiting for something to happen that is outside of your program's control.

是;纯 async 代码通常与 I/O 或其他 "events" 一起使用(例如,计时器、通知,或 - 不太常见 - 用户输入)。

What about situations when your program must perform some lengthy calculation?

这不是 async 的主要用例。但是,它是并行计算 (Parallel / PLINQ) 的一个很好的用例,或者如果工作量较小,线程池 (Task.Run).

If await is not used then control wouldn't return back to the calling function, correct? If that's the case then surely it's not even asynchronous at all.

没错;没有 awaitasync 方法实际上会 运行 同步。事实上,如果您将其键入 Visual Studio,编译器会给您一个警告,实际上是 "this method will run synchronously"。因为大多数时候,这是一个错误。

如果您想 运行 CPU-bound 线程池线程上的代码,请使用 Task.Run。您可以(通常应该)await Task.Run 返回的任务,这允许调用者将线程池工作视为异步工作(即使它实际上只是 运行 同步在后台线程上):

await Task.Run(() => ...);

如果您想要并行处理的全部功能,您可以将其包装在 Task.Run:

await Task.Run(() => Parallel.ForEach(...));

It seems BackgroundWorker is well-suited for lengthy calculations

不是真的。检索结果有点尴尬,因为很容易遗漏错误,而且结果不是 type-safe。此外,快速协调多个 BGW 变得困难。我有一个博客系列 shows how BackgroundWorker should essentially be considered obsoleted by Task.Run.