C# 异步编程:初学者完整指南
\n\n异步编程是现代 C# 开发中的关键概念之一。它使您的应用程序能够保持响应,而不会在执行长时间操作(如读取文件、数据库查询或 HTTP 调用)时阻塞执行线程。在本指南中,我们将通过实际示例讲解 C# 异步编程的基础知识。
\n\n什么是异步编程,为什么需要它?
\n\n在同步编程中,代码按顺序执行。如果您调用一个等待服务器响应 5 秒的方法,整个线程(UI 或工作线程)将停滞。应用程序会“卡住”。异步编程解决了这个问题:方法不是阻塞线程,而是将控制权返回给调用代码,并在结果准备好时通知调用方。
\n\n异步的主要优势:
\n- \n
- UI 响应性 — 界面在长时间操作期间不会卡住。 \n
- 可扩展性 — 服务器应用程序可以处理更多请求,而无需创建新线程。 \n
- 效率 — 释放的线程可用于其他任务。 \n
C# 中 async/await 的基础知识
\n\n关键字 async 和 await 是 C# 异步编程的基础。它们从 C# 5.0 开始引入,使异步代码几乎和同步代码一样简单。
使用规则:
\n- \n
- 方法使用关键字
async标记。 \n - 返回类型应为
Task、Task<T>或void(仅用于事件处理程序)。 \n - 在方法内部,使用关键字
await调用其他异步方法。 \n
简单示例:
\nusing System;\nusing System.Net.Http;\nusing System.Threading.Tasks;\n\nclass Program\n{\n static async Task Main(string[] args)\n {\n Console.WriteLine("开始下载...");\n string content = await DownloadWebPageAsync("https://example.com");\n Console.WriteLine($"已下载字符数:{content.Length}");\n }\n\n static async Task<string> DownloadWebPageAsync(string url)\n {\n using HttpClient client = new HttpClient();\n string result = await client.GetStringAsync(url);\n return result;\n }\n}\n\n请注意:Main 方法也被标记为 async Task — 从 C# 7.1 开始这是允许的。
Task、Task<T> 和 ValueTask 类型
\n\n在 C# 异步编程中,使用三种主要的返回值类型:
\n\n- \n
Task— 用于不返回值的方法(类似于 void)。 \n Task<T>— 用于返回类型 T 值的方法。 \n ValueTask<T>— 针对结果通常可同步获取的场景(例如从缓存中)的优化版本。 \n
Task<T> 示例:
\nstatic async Task<int> CalculateSumAsync(int a, int b)\n{\n await Task.Delay(1000); // 模拟长时间工作\n return a + b;\n}\n\n// 调用:\nint result = await CalculateSumAsync(5, 3);\nConsole.WriteLine(result); // 8\n\n异步方法中的错误处理
\n\n异步方法中的异常使用标准的 try-catch 块处理。但有一个重要的细节:异常会保存在 Task 对象中,并在使用 await 时重新“抛出”。
static async Task<string> ReadFileAsync(string path)\n{\n try\n {\n string content = await File.ReadAllTextAsync(path);\n return content;\n }\n catch (FileNotFoundException ex)\n {\n Console.WriteLine($"文件未找到:{ex.Message