新的C#5.0'async'和'await'关键字是否使用多个核心?

Ice*_*ind 60 c# parallel-processing asynchronous multicore c#-5.0

添加到C#5.0语言的两个新关键字是asyncawait,它们同时协同工作以异步运行C#方法而不会阻塞调用线程.

我的问题是,这些方法实际上是利用多个核并并行运行还是异步方法在与调用者相同的线程核心中运行?

Eri*_*ert 96

添加到C#5.0语言的两个新关键字是async和await,它们同时协同工作以异步运行C#方法而不会阻塞调用线程.

这符合该功能的目的,但它为async/await功能提供了太多"功劳".

让我非常非常清楚这一点:await不会神奇地导致同步方法异步运行.例如,它不会启动新线程并在新线程上运行该方法.您调用的方法必须是知道如何异步运行自身的方法.如何选择这样做是因为它的业务.

我的问题是,这些方法实际上是利用多个核并并行运行还是异步方法在与调用者相同的线程核心中运行?

同样,这完全取决于您调用的方法.所有这一切await确实是指示编译器的方法改写成可作为异步任务的延续传递的委托.也就是说,await FooAsync()"调用FooAsync()和返回的任何东西必须是代表刚刚启动的异步操作的东西.告诉那件事,当它知道异步操作完成时,它应该调用这个委托." 委托具有以下属性:当调用它时,当前方法似乎恢复"停止的位置".

如果你调用schedule的方法工作到另一个与另一个核心关联的线程,那很好.如果它启动一个计时器,将来会在UI线程上ping一些事件处理程序,那很好.await不在乎.它所做的就是确保异步作业完成后,控制可以从中断处继续.

你没有提出但可能应该提出的问题是:

当异步任务完成并且控制从中断处继续时,是否在执行与之前相同的线程?

这取决于具体情况.在winforms应用程序中,您等待来自UI线程的内容,控件在UI线程上再次获取.在控制台应用程序中,也许不是.

  • 我喜欢您在这里的解释,它确实有助于我更好地理解异步和等待。 (2认同)

Ste*_*ary 67

Eric Lippert有一个很好的答案; 我只是想进一步描述async并行性.

简单的"串行"方法是您一次await只做一件事:

static void Process()
{
  Thread.Sleep(100); // Do CPU work.
}

static async Task Test()
{
  await Task.Run(Process);
  await Task.Run(Process);
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,该Test方法将排队Process到线程池,当它完成时,它将Process再次排队到线程池.该Test方法将在~200ms后完成.在任何时候,只有一个线程真正推动了进步.

一种简单的并行化方法是使用Task.WhenAll:

static void Process()
{
  Thread.Sleep(100); // Do CPU work.
}

static async Task Test()
{
  // Start two background operations.
  Task task1 = Task.Run(Process);
  Task task2 = Task.Run(Process);

  // Wait for them both to complete.
  await Task.WhenAll(task1, task2);
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,该Test方法Process两次排队到线程池,然后等待它们两者完成.该Test方法将在~100ms后完成.

Task.WhenAll(和Task.WhenAny)介绍async/ await支持简单的并行性.但是,如果您需要更高级的东西(真正的CPU绑定并行处理更适合TPL),TPL仍然存在.TPL与async/ 配合得很好await.

我涵盖基本async在我的并行进入到async博客文章,以及"上下文"埃里克提到.