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

时间:2017-01-28 02:19:42

标签: c# asynchronous async-await backgroundworker

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

  

基于异步的异步编程方法比较好   几乎在每种情况下现有的方法。特别是这种方法   对于IO绑定操作,它比BackgroundWorker更好,因为   代码更简单,您不必防范竞争条件。   与Task.Run结合使用,异步编程优于   BackgroundWorker用于CPU绑定操作,因为异步编程   将运行代码的协调细节与工作分开   Task.Run转移到线程池。

在我看来,async函数链最终必须等待在程序控制范围之外发生的事情。一些互联网下载或用户输入或其他东西。

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

似乎BackgroundWorker非常适合冗长的计算:https://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx#Examples

有没有办法将async / await用于此目的?

2 个答案:

答案 0 :(得分:2)

关键在于:

  

结合 Task.Run ,异步编程优于   BackgroundWorker用于CPU绑定操作,因为异步编程   将运行代码的协调详细信息与工作分开   Task.Run转移到线程池。

对于受CPU限制的工作(或IO绑定,无关紧要),Task.Run将在与线程池不同的线程中运行您的代码,因此当前代码可以await,因为它在不同的线程上运行。从第二个线程的透视开始,工作是同步的,但是从第一个线程的透视开始,工作是异步的。

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

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

编辑:

您无法在await方法上使用non-awaitable。 CPU绑定任务永远不能真正异步,因为需要计算某些东西,并且需要一个线程。当前线程将执行计算(阻塞),或者将其提供给另一个后台线程,因此当前线程不会阻塞和异步。

如果您熟悉Node.js,您会发现处理CPU绑定任务非常棘手,而且通常需要重构代码。

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

答案 1 :(得分:1)

  

在我看来,一系列异步函数最终必须等待一些超出程序控制范围的事情。

是;纯async代码通常与I / O或其他“事件”一起使用(例如,定时器,通知或 - 通常 - 用户输入)。

  

当你的程序必须执行一些冗长的计算时会怎么样?

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

  

如果没有使用await,那么控制不会返回到调用函数,对吗?如果是这样的话那么肯定它根本就不是异步的。

这是正确的;没有async的{​​{1}}方法实际上会同步运行。事实上,如果你在Visual Studio中键入它,编译器会给你一个警告,实际上说“这个方法将同步运行”。因为大部分时间都是错误的。

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

Task.Run

如果您想要并行处理的全部功能,您可以将其包装在await Task.Run(() => ...); 内:

Task.Run
  

看起来BackgroundWorker非常适合冗长的计算

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

相关问题