async/await 不是语法糖,而是编译器驱动的状态机
当你写 async Task
await 的本质是“可等待对象”的约定调用
await 后的对象必须实现 GetAwaiter() 方法,返回一个具备以下成员的 awaiter:
IsCompleted:同步完成?若为 true,直接取 Result,不挂起 OnCompleted(Action):注册回调,当异步操作完成时被调用 GetResult():获取结果或抛出异常(可能含副作用,如释放资源)常见 awaitable 类型如 Task、Task
同步上下文(SynchronizationContext)决定 await 后在哪执行
await 恢复执行的位置,不取决于“谁调用了它”,而取决于当前捕获的 SynchronizationContext 或 TaskScheduler:
UI 线程(WinForms/WPF):自动捕获 UI 上下文,await 后回到原 UI 线程(避免跨线程访问控件异常) ASP.NET(旧版):捕获 HttpContext 关联的上下文,确保 Request/Response 可用 控制台/默认线程池:无上下文,await 后由任意线程池线程执行(无序、不可预测)可用 ConfigureAwait(false) 显式禁用上下文捕获,提升性能并避免死锁(尤其在库代码中强烈推荐)。
线程本身不被“切换”,但执行流被调度器接管
async/await 不创建新线程,也不强制线程切换。真正的并发来自底层 I/O(如 FileStream.ReadAsync)或任务调度(如 Task.Run)。await 挂起后,线程通常回归线程池处理其他请求;恢复时,由调度器将续体排入目标上下文(如 UI 消息队列)或线程池队列。整个过程无栈撕裂、无线程阻塞——这是它高效的关键。
基本上就这些。理解状态机构造、awaiter 协议和上下文流转,就能看透 async/await 的行为边界与性能特征。
