为什么使用C#async / await来处理CPU绑定的任务

时间:2018-02-22 13:31:11

标签: c# multithreading asynchronous async-await task-parallel-library

我在C#中获取了async / await关键字,以及它们如何促进异步编程 - 允许在其他地方使用该线程,而某些I / O绑定任务如db调用正在进行中。

我已经多次读过async / await用于I / O绑定任务,而不是CPU绑定任务。 CPU绑定任务应该在单独的后台线程上执行。在这些videos中多次提到过。一切都好。

但是,当使用Task.Run在新线程上启动长时间运行的CPU绑定工作时,您必须在某个时刻await。那么我们是否也在使用async / await来处理CPU绑定的任务呢?见下面的例子。

public async Task SomeMethodAsync()
{
    int result = await Task.Run(() =>
    {
        // Do lots of CPU bound calculations...

        return result;
    }

    // Then do something with the result.
}

2 个答案:

答案 0 :(得分:8)

无论作业是否受I / O限制,

async/await是进行异步编程的当代且最简单的方法; Task是否需要一个帖子。

例如,它非常适合WinForms或WPF,因为主线程可以await一个子任务来计算Piggy小姐在一年中吃午餐的次数(一个相当长且复杂的CPU绑定操作让& #39; s说)并且当完成执行紧接下面的下一行时。与传统的异步回调不同,它使您的代码非常直观; WaitOne或其他机制以及与之相关的杂耍行为。

MSDN:

  

通过使用异步编程,您可以避免性能瓶颈并提高应用程序的整体响应能力。但是,用于编写异步应用程序的传统技术可能复杂,这使得它们难以编写,调试和维护。

     

Visual Studio 2012引入了一种简化的方法,即异步编程,它利用.NET Framework 4.5和Windows运行时中的异步支持。 编译器执行开发人员过去的艰巨工作,并且您的应用程序保留了类似于同步代码的逻辑结构More...

OP:

  

我已多次读过async / await用于I / O绑定任务

不正确的。 async/await是异步编程的简写,编译器可以完成更多的工作。它不仅适用于I / O绑定任务。 CPU绑定任务通常使用线程池线程。

  

CPU绑定任务应该在单独的后台线程上执行。

是的......但这并不代表你await Task await。与I / O绑定任务不同的CPU绑定任务需要一个线程来运行,并且根据定义工作线程,因此将从可用线程池中获取一个。

  

但是,当使用Task.Run在新线程上启动长时间运行的CPU绑定工作时,您必须在某个时刻等待它

您不必Task await,此类任务将被称为“即发即弃”。 Task实际上并没有启动它,任务是"热"。但是,如果不等待,您将面临应用程序退出时未完成任务的风险。例如一个控制台应用程序触发Task而不等待它然后退出。

  

因此,我们是否也在使用async / await来处理CPU绑定任务?

没错,你可以将它用于任何display:flex,无论它是否受I / O限制。

更多

答案 1 :(得分:1)

如果您await某事,您承诺将从等待的操作中获得结果。通常,您期望等待的操作是异步\后台操作,将来会执行。同时,您可以继续您的工作,这可以独立于该操作的结果完成。

async/await确实是编译器帮助归档它。 await将控件返回给调用者并异步处理等待操作。可以用不同的方式提供异步性。

I / O操作将在内核空间中异步处理,因此您无需为I / O操作创建其他线程。

  

在系统API调用之后,请求现在位于内核空间中   它通往操作系统的网络子系统(例如/ net中的网络)   Linux内核)。操作系统将处理网络请求   异步。细节可能会有所不同,具体取决于使用的操作系统(   设备驱动程序调用可能被调度为发送回的信号   可以进行运行时或设备驱动程序调用,然后发送信号   返回),但最终运行时将通知网络   请求正在进行中。这时,为设备驱动程序工作   将被安排,正在进行或已经完成(   请求已经“通过电线”) - 但因为这就是全部   异步发生,设备驱动程序能够立即执行   处理其他事情!

另一方面,对于CPU操作,你必须指示CPU以异步方式执行这些操作,通常这是从不同的线程完成的(你有Task.Run的原因。)

  

CPU绑定的异步代码与I / O绑定的异步代码略有不同。   因为工作是在CPU上完成的,所以无法绕过   专门用于计算的线程。使用async和await   为您提供了一种与后台线程进行交互的简洁方法   保持异步方法的调用者响应。请注意,这样做   不为共享数据提供任何保护。如果您使用共享   数据,您仍然需要应用适当的同步   策略。

重点是,在这两种情况下,你必须await才能等待履行承诺。