6

我一直在阅读 Eric Lippert 关于 C# 5 中的异步的博文(第 4部分特别相关),并观看了 Anders PDC10 关于该主题的讨论,我不清楚如何在单线程上下文中恢复异步方法的延续。

两个消息来源都讨论了在单线程 UI 循环中使用异步方法来提高响应能力,在 Anders 的示例中,他提到当异步任务完成时,它的继续是通过向消息泵添加消息来安排的。

异步方法是否真的知道它需要执行看起来像是特定于上下文的操作,或者这是一种简化?

更一般地说,如何在单线程上下文中处理异步方法的恢复?是否需要在单个线程内进行调度?

4

2 回答 2

7

任务延续知道需要在哪里安排延续——例如“任何线程池线程”或“UI 线程”。

然而,这种行为是由“等待者”决定的——它实际上并不是 C# 编译器负责的部分。编译器只是调用BeginAwait并传入延续;等待者返回一个布尔值,指示任务是否已经同步完成,或者调用者是否应该返回并让继续异步发生。

所以目前,这个决定是在等待者返回的时候做出的——但看到这一切最终TaskEx都被捆绑在一起,我不会感到惊讶。Task这可以流动诸如同步上下文之类的东西,它知道应该如何处理进一步的操作。

我不太确定您正在考虑哪种真正的单线程上下文......或者您是否正在考虑大部分工作需要在单个线程中发生但其他线程可以参与异步位(例如,当接收到 HTTP 数据包,在 IO 完成端口线程上处理,以及在 UI 线程上处理回响应时)?

于 2011-03-21T12:30:31.827 回答
7

乔恩的回答当然很棒;我想我会再添加一件事。

考虑一个 WinForms 应用程序,该应用程序在您单击该按钮时运行代码的表单上有一个按钮。

当您单击按钮时会发生什么?没有。该进程存在,代码正在运行,但它似乎没有做任何事情。事实上,它正在做的是在 UI 线程上处理消息并确定它们都不是有趣的,但它看起来并没有做任何有趣的事情。

当您单击按钮时,突然其中一条消息很有趣,并且消息泵知道当它看到该单击事件时,它应该运行一些代码。确实如此。

单线程异步方案是一样的。延续——“任务完成后做什么”代码实际上是“任务完成”事件的“事件处理程序”。当任务完成时,它会“按下按钮”并将消息排入 UI 线程的消息队列中。无论是从 UI 线程还是从 I/O 完成线程或其他什么都没有关系。当 UI 线程开始处理该消息时,它会调用延续。就像当 UI 线程开始处理按钮单击一样,它调用单击处理程序。

于 2011-03-21T15:20:56.413 回答