"前情提要:修士李四强行同步调用异步功法,导致经脉(线程)阻塞,全身灵力(CPU资源)停滞,化作一尊代码石像...今日我们修习
async/await
无上心法,打通并发任督二脉!"
🌠 本章修仙目标
-
领悟异步本质:理解
async/await
运行机理 -
掌握多线程御剑术:精通
Task
与并行编程 -
规避走火入魔:解决死锁/竞态条件
-
炼制并发法宝:
Channel
/Parallel
实战
🧘 一、基础心法:async/await原理
1.1 同步vs异步修真对比
特性 | 同步修炼 | 异步修炼 |
---|---|---|
灵力运用 | 单经脉阻塞 | 多经脉并行 |
心法口诀 | void Method() | async Task Method() |
危险系数 | 易导致界面冻结 | 需防走火入魔(死锁) |
适用场景 | 快速简单操作 | I/O密集型/高并发 |
1.2 异步状态机运转图解
核心口诀:
"async方法遇await,立即让出线程权,待得异步结果返,恢复执行不停顿"
🧵 二、多线程御剑术
2.1 线程池 vs 独立线程
特性 | 线程池(ThreadPool ) | 独立线程(new Thread ) |
---|---|---|
创建开销 | 极小 | 较大 |
管理方式 | 自动调度 | 手动控制 |
适用场景 | 短期任务 | 长期运行任务 |
修真比喻 | 符箓(用完即焚) | 本命法宝(长期持有) |
2.2 Task并行库(TPL)实战
// 基础御剑术
Task.Run(() =>
{
Console.WriteLine($"在线程{Thread.CurrentThread.ManagedThreadId}上运行");
});
// 万剑诀(并行循环)
Parallel.For(0, 10, i =>
{
Console.WriteLine($"第{i}把飞剑,线程ID:{Thread.CurrentThread.ManagedThreadId}");
});
// 剑阵组合技
var task1 = FetchDataAsync();
var task2 = ProcessImageAsync();
await Task.WhenAll(task1, task2); // 等待所有任务完成
☯ 三、阴阳调和:同步上下文
3.1 UI线程安全心法
// WPF/WinForms中正确更新UI
async Task UpdateUIAsync()
{
var data = await GetDataAsync().ConfigureAwait(true); // 保持UI上下文
label.Text = data; // 安全访问UI控件
}
3.2 避免死锁的禁忌口诀
❌ 错误做法:
var result = GetDataAsync().Result; // 同步阻塞导致死锁
✅ 正确做法:
var result = await GetDataAsync(); // 异步等待
死锁原理图解:
💣 四、渡劫实战:并发难题破解
4.1 竞态条件防护罩
private int _counter = 0;
private readonly object _lock = new();
void SafeIncrement()
{
lock (_lock) // 锁法宝
{
_counter++;
}
}
// 更高级的原子操作
Interlocked.Increment(ref _counter);
4.2 异步流处理(Channel)
var channel = Channel.CreateUnbounded<int>();
// 生产者
_ = Task.Run(async () =>
{
for (int i = 0; i < 10; i++)
{
await channel.Writer.WriteAsync(i);
await Task.Delay(100);
}
channel.Writer.Complete();
});
// 消费者
await foreach (var item in channel.Reader.ReadAllAsync())
{
Console.WriteLine($"接收到:{item}");
}
🧪 五、经脉实验场
5.1 异步诊断工具
// 查看当前同步上下文
Console.WriteLine($"当前上下文: {SynchronizationContext.Current?.GetType().Name ?? "null"}");
// 检测异步方法状态
var status = myTask.Status; // Created, Running, Completed等
5.2 性能对比测试
// 同步版本
var syncStopwatch = Stopwatch.StartNew();
SyncMethod();
syncStopwatch.Stop();
// 异步版本
var asyncStopwatch = Stopwatch.StartNew();
await AsyncMethod();
asyncStopwatch.Stop();
Console.WriteLine($"同步耗时:{syncStopwatch.Elapsed} 异步耗时:{asyncStopwatch.Elapsed}");
📜 本章心法总诀
-
异步非多线程:I/O操作无需独占线程
-
Task是万能器:比Thread更适合现代编程
-
锁事需谨慎:能用
Interlocked
就不用lock
-
ConfigureAwait:库代码应避免捕获上下文
🔮 下章预告
第四章:符阵玄机——依赖注入与AOP
"王长老的炼丹炉因硬编码依赖,无法更换异火(实现),导致炸炉...且看
IServiceCollection
如何解耦法宝依赖!"
💬 论道阁(评论区留言)
-
你在何时遭遇过死锁危机?
-
ValueTask
与Task
该如何抉择? -
如何设计线程安全的缓存系统?
微信公众号:【.NET修仙日记】