如何直观证明异步与同步代码的执行顺序存在差异?
同步 vs 异步代码的执行顺序差异演示
同步代码:严格的顺序执行
Thing[] stuff = Context.Things .Where(a => true) .ToArray(); Console.WriteLine("Boop");
- 执行逻辑:
- 执行
ToArray()时,当前线程会被完全阻塞,直到数据库查询结束、结果转换成Thing[]数组并完成赋值 - 只有等数组创建完成后,才会执行后续的
Console.WriteLine("Boop") - 整个过程线程无法处理其他任何任务
- 执行
异步代码:非阻塞的挂起与恢复
Thing[] stuff = await Context.Things .Where(a => true) .ToArrayAsync(); Console.WriteLine("Beep");
- 执行逻辑:
- 调用
ToArrayAsync()后,方法会立即发起数据库查询请求,然后释放当前线程(线程可以去处理其他待执行的任务,比如UI事件、其他API调用) - 当数据库查询完成、结果转换成数组后,
await会触发上下文恢复,回到当前方法继续完成stuff的赋值操作 - 最后执行
Console.WriteLine("Beep")
- 调用
直观时序对比(假设存在其他待处理任务)
| 时间节点 | 同步版本行为 | 异步版本行为 |
|---|---|---|
| T1 | 启动ToArray(),线程进入阻塞状态 | 调用ToArrayAsync()发起查询,线程被释放去处理其他任务 |
| T2-Tn | 线程持续阻塞,等待数据库返回结果 | 线程在处理其他任务(例:响应前端请求、处理UI点击) |
| Tn+1 | 接收数据库结果,创建数组并赋值 | 数据库查询完成,await恢复上下文,完成数组赋值 |
| Tn+2 | 打印"Boop" | 打印"Beep" |
注意:如果没有其他待处理任务,异步版本的最终输出顺序看起来和同步版本一致,但底层线程的利用逻辑完全不同——异步不会浪费线程资源在等待IO操作上。
内容的提问来源于stack exchange,提问作者Konrad Viltersten
相关产品推荐
相关产品推荐

