异步编程使程序能够在等待长时间运行的任务时保持响应性。C# 使用 async 和 await 关键字来简化异步编程。
目录
6.1 基本概念
> async 关键字:标记方法为异步方法。
> await 关键字:等待异步操作完成。
异步编程(Async/Await)就像在餐厅点菜:
> 普通编程:你点了菜后就一直等待,不做其他事情,直到菜做好才能继续。
> 异步编程:你点了菜后可以去做其他事情,比如聊天或看电视,等菜做好了再去取。这样你就能高效地利用时间,不浪费等待的过程。
6.1.1 示例:基本异步方法
using System;
using System.Threading.Tasks;
//---
class Program
{
static async Task Main(string[] args)
{
await DoSomethingAsync();
Console.WriteLine(13213131231313);
Console.WriteLine("Async method completed.");
}
//---
static async Task DoSomethingAsync()
{
await Task.Delay(2000); // 模拟异步操作
Console.WriteLine("Something was done.");
}
}
6.1.2 示例:返回值的异步方法
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
int result = await CalculateSumAsync(5, 10);
Console.WriteLine($"Result: {result}");
}
static async Task<int> CalculateSumAsync(int a, int b)
{
await Task.Delay(1000); //模拟异步操作
return a + b;
}
}
6.1.3 异步方法中的异常处理
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
try
{
int result = await CalculateSumAsync(5, 10);
Console.WriteLine($"Result: {result}");
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
}
//---
static async Task<int> CalculateSumAsync(int a, int b)
{
await Task.Delay(1000); // 模拟异步操作
throw new InvalidOperationException("An error occurred during the calculation.");
return a + b;
}
}
6.1.4 并行执行多个异步操作
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
Task<int> task1 = CalculateSumAsync(5, 10);
Task<int> task2 = CalculateSumAsync(20, 30);
int[] results = await Task.WhenAll(task1, task2);
Console.WriteLine($"Result 1: {results[0]}");
Console.WriteLine($"Result 2: {results[1]}");
}
static async Task<int> CalculateSumAsync(int a, int b)
{
await Task.Delay(1000); // 模拟异步操作
return a + b;
}
}
using System;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
// 启动异步数据加载
Task<int> dataTask = LoadDataAsync();
// 执行其他任务
for (int i = 0; i < 10; i++)
{
Console.WriteLine($"Processing other tasks: {i + 1}/10");
await Task.Delay(500); // 模拟其他任务的工作
}
// 直接访问 dataTask 结果(不使用 await)
// 这可能会导致获取到尚未完成的任务的结果
int result = dataTask.Result;
Console.WriteLine($"Data loaded: {result}");
}
static async Task<int> LoadDataAsync()
{
Console.WriteLine("Loading data...");
await Task.Delay(3000); // 模拟网络延迟,假设数据加载需要 3 秒钟
return 42; // 模拟返回的数据
}
}
6.1.5 小结
> async:用于定义异步方法。
> await:用于等待异步操作完成。
> 返回值:异步方法可以返回 Task 或 Task<T>。
> 1 无返回值的任务:
Task.Run(() => {
// 执行一些异步操作
Console.WriteLine("Task completed.");
});
> 2 有返回值的任务:
Task<int> task = Task.Run(() => {
// 执行一些异步操作并返回结果
return 42;
});
int result = await task; // 使用 await 获取结果
Console.WriteLine($"Result: {result}");
> 异常处理:使用 try-catch 来处理异步操作中的异常。
> 并行执行:使用 Task.WhenAll 并行执行多个异步操作。
> 1 async
> 解释
> 1.1 用于标记一个方法为异步方法,表示该方法可以包含 await 表达式。
> 1.2 异步方法必须返回 Task、Task<TResult> 或 void(虽然不推荐使用 void)。
> 1.3 例如:
async Task<int> CalculateSumAsync(int a, int b)
{
return a + b;
}
> 2 await
> 解释
> 1.1 用于等待异步操作完成,并获取其结果。
> 1.2 只能在标记为 async 的方法中使用。
> 1.3 例如:
int result = await CalculateSumAsync(5, 10);
> 3 Task
> 解释
> 1.1 表示一个异步操作,Task 是无返回值的,Task<TResult> 是有返回值的。
> 1.2 可以通过 Task 对象的 Result 属性获取结果(但通常不推荐,因为它可能会阻塞线程)。
> 4 Task.Run
> 解释
> 1.1 用于启动一个新的异步操作,将其安排在线程池中执行。
> 1.2 例如:
Task.Run(() => {
// 执行一些异步操作
});
> 5 Task.WhenAll
> 解释
> 1.1 用于等待异步操作完成,并获取其结果。
> 1.2 例如:
await Task.WhenAll(task1, task2, task3);
> 6 Task.WhenAny
> 解释
> 1.1 用于等待一组异步操作中任意一个完成,并返回一个 Task,该任务在其中一个任务完成时完成。
> 1.2 例如:
Task completedTask = await Task.WhenAny(task1, task2, task3);
> 7 Task.Delay
> 解释
> 1.1 用于创建一个延迟的异步任务,通常用于模拟等待时间或延迟操作。
> 1.2 例如:
await Task.Delay(1000); // 延迟 1 秒
> 8 Task.FromResult
> 解释
> 1.1 用于创建一个已完成的 Task,并返回指定的结果。
> 1.2 例如:
Task<int> completedTask = Task.FromResult(42);
> 9 Task.CompletedTask
> 解释
> 1.1 用于获取一个已完成的 Task 对象,通常用于没有返回值的异步操作。
> 1.2 例如:
Task completedTask = Task.CompletedTask;
> 10 Task.Factory.StartNew
> 解释
> 1.1 用于创建并启动一个任务,这个方法提供了更多的配置选项,但在大多数情况下,使用 Task.Run 更为常见。
> 1.2 例如:
Task task = Task.Factory.StartNew(() => {
// 执行某些工作
});