文章速览
- 一、何时使用async/await
- 二、深度分析:为什么在此类场景中频繁出现?
-
- 1.web应用的线程池机制
- [2.Entity Framework Core的设计](#2.Entity Framework Core的设计)
- 三、同步vs异步对比分析
- 总结
一个赞,留下专属于你的足迹!
一、何时使用async/await
1.核心判断标准
| 场景 | 是否使用 async | 原因 |
|---|---|---|
| I/O 操作(数据库、文件、网络请求) | ✅ 必须用 | 释放线程,提高并发 |
| CPU 密集型计算 | ❌ 不需要 | 应该使用 Task.Run 或直接同步 |
| 纯内存操作 | ❌ 不需要 | 增加复杂度,无性能收益 |
2.示例代码
csharp
// ✅ 数据库查询 - 需要 async
public async Task<string> GetAllBigClassAsync()
{
var list = await _context.BigClasses.ToListAsync(); // I/O 操作
return JsonSerializer.Serialize(list);
}
// ✅ 数据库保存 - 需要 async
public async Task<string> DeleteNumberDataAsync(int dataId, int userId)
{
var user = await _context.Users.FindAsync(userId); // I/O 操作
// ... 修改数据
await _context.SaveChangesAsync(); // I/O 操作
}
二、深度分析:为什么在此类场景中频繁出现?
1.web应用的线程池机制
在ASP.NET Core中,线程池是有限的,大约1000个线程。假设不用async:
csharp
// ❌ 同步版本(阻塞线程)
public string GetAllBigClassSync()
{
var list = _context.BigClasses.ToList(); // 线程被卡住,等待数据库返回
return JsonSerializer.Serialize(list);
}
出现的问题是:当1000个用户同时请求时,线程池耗尽,第1001个用户必须等待。
使用async后:
- 发出数据库请求后,当前线程立刻释放,可以处理其他用户请求
- 数据库返回数据后,从线程池取一个空闲线程继续执行
- 并发能力提升10-100倍
2.Entity Framework Core的设计
EF Core从底层支持异步,所有的I/O方法都有Async后缀:
csharp
// 在你的代码中出现的 EF Core 异步方法:
await _context.BigClasses.ToListAsync();
await _context.NumberRecords.FindAsync(dataId);
await _context.SaveChangesAsync();
await _context.NumberRecords
.Where(d => d.DataState == 1)
.CountAsync();
await _context.Database.BeginTransactionAsync();
关键点:数据库查询是网络I/O,不是CPU计算,也正是async的最佳场景。
三、同步vs异步对比分析
1.代码对比
| 维度 | 同步方法 | 异步方法(你的代码) |
|---|---|---|
| 方法签名 | string GetData() |
async Task<string> GetDataAsync() |
| 数据库查询 | .ToList() |
await .ToListAsync() |
| 线程行为 | 阻塞线程,干等 | 释放线程,回调继续 |
| 并发能力 | 低(线程池耗尽) | 高(支撑万级并发) |
| 代码复杂度 | 简单直接 | 需要 async/await 链 |
2.执行流程对比
假设一个请求需要查询数据库(耗时100ms):
同步版本:
时间点: 线程1状态
0ms 开始执行->发送sql->阻塞等待
100ms 收到结果->返回Json
期间线程1被完全占用,无法处理其他请求
异步版本:
时间点: 线程1状态 线程2状态
0ms 开始执行->发送sql->立刻释放 处理其他请求
100ms 空闲 收到结果->继续执行->返回Josn
总结
| 项目类型 | 推荐做法 | 原因 |
|---|---|---|
| Web API / Razor Pages | 全面使用 async | I/O 密集,并发要求高 |
| 后台定时任务 | 可部分使用同步 | 单线程执行,无需高并发 |
| WinForm/WPF | async + ConfigureAwait(false) | 避免 UI 线程死锁 |
| 计算密集型(图像处理、大数据计算) | 同步或 Task.Run |
不是 I/O,async 无收益 |