面试题答案
一键面试1. 基于回调的异步编程
- 原理:将一个方法(回调函数)作为参数传递给发起异步操作的方法,当异步操作完成时,调用该回调函数。
- 优点:简单直接,在早期的异步编程中广泛应用。
- 缺点:代码可读性差,容易出现回调地狱(多层嵌套回调)。
- 适用场景:简单的异步操作,并且不需要复杂的控制流程。
2. IAsyncResult模式
- 原理:通过实现IAsyncResult接口来表示异步操作的状态,BeginXxx方法开始异步操作并返回IAsyncResult,EndXxx方法等待异步操作完成并获取结果。
- 优点:提供了一种标准的异步编程模式,可用于多种异步场景。
- 缺点:代码较为繁琐,需要手动管理异步状态和资源。
- 适用场景:需要对异步操作进行更底层控制,如自定义异步操作的状态管理。
3. 异步委托
- 原理:委托本身提供了BeginInvoke和EndInvoke方法来实现异步调用,原理类似IAsyncResult模式,但基于委托简化了实现。
- 优点:基于委托,代码相对简洁,适合熟悉委托的开发者。
- 缺点:同样存在代码繁琐问题,且处理复杂异步场景能力有限。
- 适用场景:简单的异步委托调用场景,对代码简洁性有一定要求。
4. Task异步编程模型
- 原理:Task类代表一个异步操作,通过Task.Run等方法启动异步任务,可使用await等待任务完成。
- 优点:代码简洁,支持链式调用,方便处理多个异步任务的组合与并发。
- 缺点:在较老的框架版本中支持性可能不足。
- 适用场景:大多数现代异步编程场景,尤其是需要处理多个异步任务并发或顺序执行的情况。
5. async/await关键字
- 原理:基于Task异步编程模型,async关键字标记一个异步方法,await关键字暂停异步方法的执行,直到其等待的Task完成。
- 优点:使异步代码看起来像同步代码,极大提高了代码的可读性和可维护性。
- 缺点:需要.NET Framework 4.5及以上版本支持。
- 适用场景:所有适合使用Task异步编程模型的场景,尤其是对代码可读性要求高的项目。
复杂异步代码示例
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
CancellationTokenSource cts = new CancellationTokenSource();
try
{
// 启动多个异步任务
Task task1 = Task.Run(() => LongRunningTask("Task 1", cts.Token), cts.Token);
Task task2 = Task.Run(() => LongRunningTask("Task 2", cts.Token), cts.Token);
// 按顺序等待任务完成
await task1;
await task2;
Console.WriteLine("All tasks completed successfully.");
}
catch (OperationCanceledException)
{
Console.WriteLine("One or more tasks were cancelled.");
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}
finally
{
cts.Dispose();
}
}
static async Task LongRunningTask(string taskName, CancellationToken cancellationToken)
{
for (int i = 0; i < 10; i++)
{
if (cancellationToken.IsCancellationRequested)
{
cancellationToken.ThrowIfCancellationRequested();
}
Console.WriteLine($"{taskName} is running step {i}");
await Task.Delay(1000);
}
}
}
在上述代码中:
- 异常处理:使用try - catch块捕获异步操作中可能抛出的异常,包括任务取消异常
OperationCanceledException
和其他一般性异常。 - 取消任务:通过
CancellationTokenSource
和CancellationToken
实现任务取消,在异步任务执行过程中检查CancellationToken
的状态并适时抛出OperationCanceledException
。 - 协调任务执行顺序:通过
await
关键字按顺序等待多个异步任务完成,先等待task1
完成,再等待task2
完成。