C# async/await - 程序如何跟踪“await”调用的位置?

3
当运行线程遇到一个await时,内部使用什么机制来“标记”该特定方法最终需要在等待的任务完成后恢复? 考虑以下方法:
public async void DoSomething()
{
   await Task.Run(() => SomeLongRunningWork());
   // Code to resume when the task is done...
   Console.WriteLine("Resuming...");
}

当达到上述 await 时,线程池中的一个线程将用于执行长时间运行的任务。此外,调用线程立即退出 DoSomething() 方法,并在任务完成后“返回”。
调用线程如何知道在某个时候“回来”呢?内部发生了什么以实现这一点?

3
简单来说,编译器将await关键字后面的代码封装成一个“续体”,并将其作为任务完成后应运行的代码传递给任务。这比我描述的更为复杂(例如,需要等待器确定续体应在哪个线程上运行,如何处理异常等)。当async/await即将发布时,有很多优秀的博客和MSDN文章详细讨论了这一点。 - Flydog57
1
其中之一的文章在这里:https://weblogs.asp.net/dixin/understanding-c-sharp-async-await-1-compilation - Roman Kalinchuk
1个回答

3
当一个方法包含await时,编译器会创建所谓的异步状态机。被等待的任务被存储下来,await后面的所有内容都被标记为该任务的继续执行部分。
通过状态机、AsyncTaskMethodBuilder<>TaskAwaiter<>,基础架构跟踪执行和同步上下文,捕获本地变量,并最终跟踪原始Task状态,同时等待其完成。它通过循环(调用内部的MoveNext方法)来实现这一点,直到任务完成、被取消或因异常而失败。假设前者,那么继续执行将在适当的上下文中调用。当抛出异常时,AggregateException(通常会在Task中得到)会被“解开”(抛出第一个异常),以模仿正常的同步方法体验。

这只是整体上的简化。有各种各样的优化和大量的机制使得所有这些工作都能正常运行。关于此主题的一篇好博客,我建议参考这个Microsoft系列关于异步方法的文章。


谢谢,这正是我在寻找的! - Struessel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接