C Sharp async 与await
C# async与await[编辑 | 编辑源代码]
介绍[编辑 | 编辑源代码]
async和await是C#中用于简化异步编程的关键字,它们使得编写异步代码更加直观和易于维护。通过使用这两个关键字,开发者可以编写出看起来像同步代码的异步代码,从而避免回调地狱(Callback Hell)并提高代码的可读性。
异步编程的核心目标是让程序在等待某些操作(如I/O操作、网络请求等)完成时,不会阻塞主线程,从而提高应用程序的响应性和吞吐量。
基本语法[编辑 | 编辑源代码]
在C#中,`async`关键字用于标记一个方法为异步方法,而`await`关键字用于等待一个异步操作的完成。异步方法通常返回`Task`或`Task<T>`。
示例1:简单的异步方法[编辑 | 编辑源代码]
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("开始执行异步方法");
await DoSomethingAsync();
Console.WriteLine("异步方法执行完成");
}
static async Task DoSomethingAsync()
{
Console.WriteLine("异步操作开始");
await Task.Delay(2000); // 模拟耗时操作
Console.WriteLine("异步操作结束");
}
}
输出:
开始执行异步方法 异步操作开始 (等待2秒) 异步操作结束 异步方法执行完成
解释: - `Main`方法标记为`async`,因此可以在其中使用`await`。 - `DoSomethingAsync`方法模拟了一个耗时操作(`Task.Delay`)。 - `await`会暂停当前方法的执行,直到`Task.Delay`完成,但不会阻塞主线程。
工作原理[编辑 | 编辑源代码]
当遇到`await`时,C#会将当前方法的剩余部分包装为一个回调,并在异步操作完成后继续执行。以下是`async`/`await`的工作流程:
返回值类型[编辑 | 编辑源代码]
异步方法可以返回以下类型: 1. `Task`:表示没有返回值的异步操作。 2. `Task<T>`:表示返回类型为`T`的异步操作。 3. `void`:通常用于事件处理程序,但不推荐在其他场景使用。
示例2:返回值的异步方法[编辑 | 编辑源代码]
static async Task<int> CalculateSumAsync(int a, int b)
{
await Task.Delay(1000); // 模拟耗时计算
return a + b;
}
static async Task Main(string[] args)
{
int result = await CalculateSumAsync(3, 5);
Console.WriteLine($"计算结果: {result}");
}
输出:
(等待1秒) 计算结果: 8
错误处理[编辑 | 编辑源代码]
异步方法可以通过`try-catch`块捕获异常,就像同步代码一样。
示例3:异步异常处理[编辑 | 编辑源代码]
static async Task ThrowExceptionAsync()
{
await Task.Delay(1000);
throw new InvalidOperationException("发生了错误!");
}
static async Task Main(string[] args)
{
try
{
await ThrowExceptionAsync();
}
catch (InvalidOperationException ex)
{
Console.WriteLine($"捕获异常: {ex.Message}");
}
}
输出:
(等待1秒) 捕获异常: 发生了错误!
实际应用场景[编辑 | 编辑源代码]
1. 文件I/O操作:异步读取或写入文件以避免阻塞UI线程。 2. 网络请求:如HTTP API调用。 3. 数据库操作:异步查询或更新数据库。
示例4:异步HTTP请求[编辑 | 编辑源代码]
using System;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
using HttpClient client = new HttpClient();
string url = "https://api.example.com/data";
try
{
string response = await client.GetStringAsync(url);
Console.WriteLine($"响应数据: {response}");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"请求失败: {ex.Message}");
}
}
}
常见问题与注意事项[编辑 | 编辑源代码]
1. 避免`async void`:除非是事件处理程序,否则应使用`async Task`。 2. 死锁风险:在UI线程中错误地使用`.Result`或`.Wait()`可能导致死锁。 3. 性能开销:异步操作有轻微的性能开销,但对于I/O密集型任务利大于弊。
数学表示(可选)[编辑 | 编辑源代码]
异步操作的完成时间可以表示为: 其中: - 是异步操作本身的耗时。 - 是回调执行的耗时。
总结[编辑 | 编辑源代码]
`async`和`await`是C#异步编程的核心,它们让开发者能够以同步的方式编写异步代码,同时保持代码的清晰性和可维护性。通过合理使用这两个关键字,可以显著提升应用程序的性能和用户体验。