"前情提要:修士李四强行同步调用异步功法,导致经脉(线程)阻塞,全身灵力(CPU资源)停滞,化作一尊代码石像...今日我们修习
async/await
无上心法,打通并发任督二脉!"
async/await
运行机理Task
与并行编程Channel
/Parallel
实战特性 | 同步修炼 | 异步修炼 |
---|---|---|
灵力运用 | 单经脉阻塞 | 多经脉并行 |
心法口诀 | void Method() | async Task Method() |
危险系数 | 易导致界面冻结 | 需防走火入魔(死锁) |
适用场景 | 快速简单操作 | I/O密集型/高并发 |
核心口诀:
"async方法遇await,立即让出线程权,待得异步结果返,恢复执行不停顿"
特性 | 线程池(ThreadPool) | 独立线程(new Thread) |
---|---|---|
创建开销 | 极小 | 较大 |
管理方式 | 自动调度 | 手动控制 |
适用场景 | 短期任务 | 长期运行任务 |
修真比喻 | 符箓(用完即焚) | 本命法宝(长期持有) |
// 基础御剑术
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); // 等待所有任务完成
// WPF/WinForms中正确更新UI
async Task UpdateUIAsync()
{
var data = await GetDataAsync().ConfigureAwait(true); // 保持UI上下文
label.Text = data; // 安全访问UI控件
}
❌ 错误做法:
var result = GetDataAsync().Result; // 同步阻塞导致死锁
✅ 正确做法:
var result = await GetDataAsync(); // 异步等待
死锁原理图解:
private int _counter = 0;
privatereadonlyobject _lock = new();
void SafeIncrement()
{
lock (_lock) // 锁法宝
{
_counter++;
}
}
// 更高级的原子操作
Interlocked.Increment(ref _counter);
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();
});
// 消费者
awaitforeach (var item in channel.Reader.ReadAllAsync())
{
Console.WriteLine($"接收到:{item}");
}
// 查看当前同步上下文
Console.WriteLine($"当前上下文: {SynchronizationContext.Current?.GetType().Name ?? "null"}");
// 检测异步方法状态
var status = myTask.Status; // Created, Running, Completed等
// 同步版本
var syncStopwatch = Stopwatch.StartNew();
SyncMethod();
syncStopwatch.Stop();
// 异步版本
var asyncStopwatch = Stopwatch.StartNew();
await AsyncMethod();
asyncStopwatch.Stop();
Console.WriteLine($"同步耗时:{syncStopwatch.Elapsed} 异步耗时:{asyncStopwatch.Elapsed}");
Interlocked
就不用lock
第四章:符阵玄机——依赖注入与AOP
"王长老的炼丹炉因硬编码依赖,无法更换异火(实现),导致炸炉...且看
IServiceCollection
如何解耦法宝依赖!"
ValueTask
与Task
该如何抉择?