新的C#5.0“asynchronous”和“等待”关键字使用多个核心吗?

添加到C#5.0语言中的两个新关键字是asynchronous和等待的 ,这两个关键字可以asynchronous运行C#方法,而不会阻塞调用线程。

我的问题是,这些方法是否真的利用了多个内核并行运行,或者async方法在调用者的同一个线程核心中运行?

添加到C#5.0语言中的两个新关键字是asynchronous和等待的,这两个关键字可以asynchronous运行C#方法,而不会阻塞调用线程。

这就是function的目的 ,但它给asynchronous/等待function提供了太多的“功劳”。

让我在这一点上非常非常清楚: await不会奇迹般地导致同步方法asynchronous运行。 例如,它不会启动新线程并在新线程上运行该方法。 你所调用的方法必须是知道如何asynchronous运行的方法。 它如何select这样做是其业务。

我的问题是,这些方法是否真的利用了多个内核并行运行,或者async方法在调用者的同一个线程核心中运行?

再一次,这完全取决于你所调用的方法 。 所有await事情都是指示编译器将方法重写成可以作为asynchronous任务的继续传递的委托。 也就是说, await FooAsync()意思是“调用FooAsync() ,返回的内容必须是表示asynchronous操作的东西,告诉事情当它知道asynchronous操作完成时,它应该调用这个委托“。 委托具有的属性是,当它被调用时,当前方法似乎恢复“停止的地方”。

如果你调用调度的方法工作到另一个线程affinitized到另一个核心,很好。 如果它启动一个计时器,在UI线程上将来会ping一些事件处理程序,那么太棒了。 await不在乎。 它所做的只是确保当asynchronous作业完成时,控制可以从停止的地方恢复。

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

当asynchronous任务完成并且控制器从中断的地方执行时,是否在与之前相同的线程中执行?

这取决于上下文。 在从UI线程中等待某些东西的WinForms应用程序中,控件在UI线程上再次拾取。 在控制台应用程序中,可能不是。

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); } 

在这个例子中, 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); } 

在这个例子中, Test方法将Process排队到线程池两次,然后等待它们都完成。 Test方法将在〜100ms后完成。

Task.WhenAll (和Task.WhenAny )引入async / await来支持简单的并行。 但是,如果您需要更高级的TPL(真正的CPU绑定并行处理更适合TPL),则TPL仍然存在。 TPL与async / await很好地结合在一起。

我介绍了基本的async并行性到async博客post ,以及埃里克提到的“背景”。

asynchronous方法返回一个等待对象(具有GetAwaiter方法的对象),如果用await关键字调用该方法,则编译器可以生成代码以使用该对象。 您也可以自由地调用这样一个没有 await关键字的方法,并明确地使用这个对象。

该对象封装了一个asynchronous操作,该asynchronous操作可能会或可能不会在另一个线程上运行。 Eric Lippert 在C#5.0中的文章Asynchrony第四部分:这不是魔术,它考虑了一个只涉及一个线程的asynchronous编程的例子。

由于asyncawait是基于TPL,他们应该非常相似地工作。 默认情况下,你应该把它们看作是在一个单独的线程上运行。