C#-异步
在 C# 中,async/await 与 Task 提供了现代化的异步编程模型(TAP),让代码既保持同步的可读性,又能避免阻塞线程,从而提升应用的响应性与性能。
通过合理使用 C# 异步特性,可以让应用在保持代码清晰的同时,显著提升性能与用户体验。
核心原理
是:await 会在等待的任务未完成时让出当前线程,任务完成后恢复执行等待点之后的代码。编译器会生成状态机保存上下文,确保恢复时环境一致。
基本用法示例
下面的示例展示了如何并行启动多个任务,并在全部完成后更新 UI 或输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| using System; using System.Collections.Generic; using System.Threading.Tasks; class Program { static async Task Main() { Console.WriteLine("开始准备早餐..."); var eggsTask = FryEggsAsync(2); var hashBrownTask = FryHashBrownsAsync(3); var toastTask = MakeToastWithButterAndJamAsync(2); await Task.WhenAll(eggsTask, hashBrownTask, toastTask); Console.WriteLine("早餐准备完成!"); } static async Task<string> FryEggsAsync(int count) { Console.WriteLine($"煎 {count} 个鸡蛋..."); await Task.Delay(3000); return "鸡蛋完成"; } static async Task<string> FryHashBrownsAsync(int count) { Console.WriteLine($"煎 {count} 个薯饼..."); await Task.Delay(3000); return "薯饼完成"; } static async Task<string> MakeToastWithButterAndJamAsync(int slices) { Console.WriteLine($"烤 {slices} 片面包..."); await Task.Delay(2000); Console.WriteLine("抹黄油和果酱"); return "吐司完成"; } }
|
要点解析
避免阻塞:不要用 .Wait() 或 .Result,应使用 await 保持线程可用。
并行执行:先启动任务,最后统一 await Task.WhenAll,减少总耗时。
任务组合:异步方法中可包含同步步骤,整体仍是异步操作。
异常处理:await 会在任务失败时抛出异常,可用 try/catch 捕获;多个异常会封装在 AggregateException 中。
UI 场景:在 WinForms/WPF 中,await 默认会回到原同步上下文,可直接更新控件;使用 Task.Run 时需 Invoke 回 UI 线程。
最佳实践
优先 async/await,减少显式线程管理。
I/O 密集型 用异步 API(如 HttpClient.GetAsync),
CPU 密集型 用 Task.Run 封装。
组合任务 用 Task.WhenAll 或 Task.WhenAny 提高效率。避免 async void,除非是事件处理器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| static async Task<object[]> FryEggsAsync(int count) { IAssemblyDoc assemblyDoc = (IAssemblyDoc)model;
Console.WriteLine($" {count} 还原..."); await Task.Delay(13000); Console.WriteLine($" {count} 还原完成..."); object[] Components = assemblyDoc.GetComponents(false); return Components; } private async void button9_Click(object sender, EventArgs e) { var eggsTask = FryEggsAsync(2);
string 施工单号 = (string)this.Invoke((MethodInvoker)delegate { Microsoft.VisualBasic.Interaction.InputBox("施工单号", "", "施工单号"); }); object[] Components = await eggsTask; }
|
参考
C# 异步编程精要