async/await 本身不决定并行或串行,关键在 Promise 创建时机和等待方式;并发需提前调用异步函数再 await Promise.all,串行则是连续 await;常见瓶颈包括隐式串行化、状态机开销及异常未处理。

async/await 本身不决定“并行”还是“串行”,它只控制代码的暂停与恢复时机;真正影响执行顺序和性能的,是 Promise 的创建时机和等待方式。
执行顺序的本质:Promise 创建即启动
await 只是等待一个已存在的 Promise 完成,并不会触发异步操作。关键在「什么时候调用异步函数」:
- ✅ 并发执行:提前调用所有异步函数(如
fetchUser()、fetchPosts()),得到 Promise 实例后,再用await Promise.all([...])统一等待 → 所有请求同时发出 - ❌ 串行执行:连续写多个 await(
await fetchUser(); await fetchPosts();)→ 后一个请求必须等前一个完全结束才开始
三大常见性能瓶颈
1. 隐式串行化
最普遍的问题:误以为多个 await 天然并发。实际是语法糖下的线性流程,I/O 时间被累加。
2. 状态机与上下文开销
每个 async 函数编译后生成状态机,高频调用会增加内存分配和 GC 压力;在 UI 或 ASP.NET 等需同步上下文的环境里,await 默认捕获 SynchronizationContext,带来调度延迟。
3. 异常未处理或 Fire-and-Forget
忘记 try/catch 导致未捕获 rejection;或调用 async 方法却不 await(尤其在事件处理器外),任务后台运行、异常丢失、资源泄漏。
快速排查与优化建议
- 检查异步调用是否在 await 前就已发起(而不是写在 await 后面)
- 对独立 I/O 操作,优先用
Promise.all或Promise.allSettled替代链式 await - 在非 UI/非 ASP.NET Core 请求上下文场景,可加
await xxx().ConfigureAwait(false)避免上下文切换 - 避免在循环中无条件 await(如逐条发请求),改用 map + Promise.all 实现批量并发
- 不用 async void(除 UI 事件处理器),统一返回 Task 或 Promise
性能差距不是理论值——3 个各耗时 1s 的 API,串行要 3s,合理并发只需约 1s。问题不在 async/await 本身,而在如何组织异步任务的生命周期。


















