新的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编程的例子。
由于async
和await
是基于TPL,他们应该非常相似地工作。 默认情况下,你应该把它们看作是在一个单独的线程上运行。