横琴网站建设公司,线上推广销售渠道,橙云网站建设,网站建设的作用和意义C# 异步编程详解
一、异步编程基础概念
1. 同步 vs 异步
同步(Synchronous)#xff1a;任务按顺序执行#xff0c;前一个任务完成后才会执行下一个异步(Asynchronous)#xff1a;任务可以非阻塞地启动#xff0c;主线程可以继续执行其他操作
2. 异步编…C# 异步编程详解
一、异步编程基础概念
1. 同步 vs 异步
同步(Synchronous)任务按顺序执行前一个任务完成后才会执行下一个异步(Asynchronous)任务可以非阻塞地启动主线程可以继续执行其他操作
2. 异步编程的优势
提高应用程序响应能力特别是UI应用更好地利用系统资源避免线程阻塞提高吞吐量
二、C#异步编程模型
1. async/await关键字
public async Taskstring GetDataAsync()
{// 模拟耗时操作await Task.Delay(1000);return Data loaded;
}// 使用
var data await GetDataAsync();
Console.WriteLine(data);
关键点
async修饰方法表示该方法包含异步操作await关键字用于等待异步操作完成异步方法返回Task或TaskT
2. Task和Task
// 返回void的异步方法仅用于事件处理
public async void HandleButtonClick()
{await SomeAsyncOperation();
}// 返回Task的异步方法
public async Task ProcessDataAsync()
{await File.ReadAllTextAsync(data.txt);
}// 返回TaskT的异步方法
public async Taskint CalculateSumAsync(IEnumerableint numbers)
{return await Task.Run(() numbers.Sum());
}
Task状态
Created已创建但未启动WaitingForActivation等待激活WaitingToRun等待运行Running正在运行RanToCompletion已完成Canceled已取消Faulted出错
三、异步方法实现方式
1. 基于I/O的异步操作
// 文件I/O
public async Task ReadFileAsync(string path)
{using (var reader File.OpenText(path)){var content await reader.ReadToEndAsync();Console.WriteLine(content);}
}// 网络I/O
public async Task DownloadDataAsync(string url)
{using (var client new HttpClient()){var response await client.GetStringAsync(url);Console.WriteLine(response);}
}
2. 基于CPU的异步操作
// 使用Task.Run将CPU密集型工作转移到线程池
public async Task ProcessDataAsync(IEnumerableint data)
{var result await Task.Run(() {// CPU密集型计算return data.Sum(x x * x);});Console.WriteLine($Sum: {result});
}
注意对于真正的并行计算考虑使用Parallel.For或PLINQ
3. 组合多个异步操作
// 等待多个任务完成
public async Task ProcessMultipleAsync()
{var task1 GetDataAsync();var task2 GetOtherDataAsync();// 等待所有完成await Task.WhenAll(task1, task2);Console.WriteLine($Data1: {task1.Result}, Data2: {task2.Result});
}// 等待任意一个完成
public async Task ProcessAnyAsync()
{var task1 GetDataAsync();var task2 GetOtherDataAsync();var completedTask await Task.WhenAny(task1, task2);Console.WriteLine($Completed: {completedTask task1 ? Task1 : Task2});
}
四、异步编程最佳实践
1. 避免async void
// 不推荐 - 无法捕获异常
public async void DangerousMethod()
{throw new Exception(Oops!);
}// 推荐 - 可以await或等待
public async Task SafeMethodAsync()
{await Task.Delay(100);throw new Exception(Oops!);
}
例外事件处理程序可以使用async void
2. 异常处理
public async Task HandleExceptionsAsync()
{try{await SomeAsyncOperation();}catch (Exception ex){// 处理异常Console.WriteLine($Error: {ex.Message});}
}// 多个任务的异常处理
public async Task HandleMultipleExceptionsAsync()
{try{await Task.WhenAll(Operation1(),Operation2(),Operation3());}catch (AggregateException ae){foreach (var ex in ae.InnerExceptions){Console.WriteLine($Error: {ex.Message});}}
}
3. 取消异步操作
// 使用CancellationToken
public async Task LongRunningOperationAsync(CancellationToken token)
{for (int i 0; i 100; i){token.ThrowIfCancellationRequested();await Task.Delay(100, token);Console.WriteLine($Step {i});}
}// 使用示例
var cts new CancellationTokenSource();
try
{await LongRunningOperationAsync(cts.Token);
}
catch (OperationCanceledException)
{Console.WriteLine(Operation was canceled);
}// 取消操作
cts.Cancel();
4. 异步方法设计原则
返回Task而非void除非是事件处理程序避免在异步方法中使用Result或Wait()可能导致死锁保持异步方法链避免混合同步和异步代码考虑异步方法的粒度不要过度拆分
五、异步与并行编程
1. 异步 vs 并行
特性异步编程并行编程目标非阻塞执行同时执行多个任务线程使用通常不创建新线程使用多个线程适用场景I/O密集型操作CPU密集型操作关键字async/awaitParallel.For/ForEach
2. 混合使用示例
public async Task ProcessDataAsync(IEnumerableData data)
{// 并行处理数据项var processedData data.AsParallel().Select(d ProcessItem(d)).ToList();// 异步保存结果await SaveResultsAsync(processedData);
}private Data ProcessItem(Data d)
{// CPU密集型处理return new Data { /* ... */ };
}private async Task SaveResultsAsync(IEnumerableData data)
{// 异步保存到数据库await _dbContext.BulkInsertAsync(data);
}
六、异步编程中的常见问题
1. 死锁问题
错误示例
public async Task DeadlockExample()
{await Task.Run(async () {// 在UI线程上调用Wait()会导致死锁await SomeAsyncOperation().ConfigureAwait(false); // 解决方案}).Wait(); // 阻塞调用
}
解决方案
使用ConfigureAwait(false)非UI上下文避免在异步方法中调用.Result或.Wait()使用await而不是Task.Run包装异步操作
2. 上下文保留问题
// 默认情况下await会捕获当前上下文如UI线程
public async Task UpdateUIAsync()
{var data await GetDataAsync();// 自动回到UI线程textBox.Text data;
}// 如果不需要回到原始上下文
public async Task ProcessInBackgroundAsync()
{var data await GetDataAsync().ConfigureAwait(false);// 不会回到原始上下文ProcessData(data);
}
3. 性能优化
避免过度异步化
// 不必要的异步包装
public async Task UnnecessaryAsync()
{await Task.Run(() {// 同步操作Thread.Sleep(1000);});
}
正确做法
只对真正的I/O操作使用异步对CPU密集型操作考虑并行处理避免在热路径上使用异步如游戏循环
七、高级异步模式
1. 异步流(IAsyncEnumerable)
// 生成异步流
public async IAsyncEnumerableint GenerateNumbersAsync(int count)
{for (int i 0; i count; i){await Task.Delay(100); // 模拟异步操作yield return i;}
}// 使用异步流
await foreach (var number in GenerateNumbersAsync(10))
{Console.WriteLine(number);
}
2. 异步锁
private readonly SemaphoreSlim _semaphore new(1, 1);public async Task ProtectedOperationAsync()
{await _semaphore.WaitAsync();try{// 受保护的代码}finally{_semaphore.Release();}
}
3. 异步工厂模式
public interface IAsyncFactoryT
{TaskT CreateAsync();
}public class AsyncDataFactory : IAsyncFactoryData
{public async TaskData CreateAsync(){await Task.Delay(100); // 模拟异步初始化return new Data();}
}
八、异步测试
1. 单元测试异步方法
[Fact]
public async Task TestAsyncMethod()
{// Arrangevar service new MyService();// Actvar result await service.GetAsync();// AssertAssert.NotNull(result);
}// 使用Moq测试异步方法
[Fact]
public async Task TestWithMock()
{var mock new MockIRepository();mock.Setup(r r.GetDataAsync()).ReturnsAsync(new Data { Id 1 });var service new MyService(mock.Object);var result await service.GetData();Assert.Equal(1, result.Id);
}
2. 测试异步代码中的异常
[Fact]
public async Task TestException()
{// Arrangevar service new FaultyService();// Act Assertawait Assert.ThrowsAsyncInvalidOperationException(() service.FaultyOperationAsync());
}
九、异步性能监控
1. 使用DiagnosticSource
// 在异步方法中添加诊断事件
private static readonly DiagnosticSource _diagnosticSource new DiagnosticListener(MyAsyncComponent);public async Task ProcessAsync()
{if (_diagnosticSource.IsEnabled(StartProcess)){_diagnosticSource.Write(StartProcess, new { Timestamp DateTime.UtcNow });}await Task.Delay(100);if (_diagnosticSource.IsEnabled(EndProcess)){_diagnosticSource.Write(EndProcess, new { Duration 100 });}
}
2. 使用AsyncLocal跟踪上下文
private static readonly AsyncLocalstring _context new();public async Task OperationWithContext()
{_context.Value OperationStarted;await Task.Delay(100);Console.WriteLine(_context.Value); // 仍然可以访问
}
十、异步编程的未来发展
1. C#中的新特性
C# 8.0IAsyncEnumerableC# 9.0异步流改进C# 10.0更高效的异步方法生成
2. .NET中的改进
.NET Core 3.0更好的异步IO性能.NET 5统一的异步API.NET 6更智能的异步调度器
十一、最佳实践总结
优先使用async/await而非ContinueWith或Task.Result在UI应用中确保异步操作回到UI线程使用ConfigureAwait(false)谨慎避免混合同步和异步代码如Wait()和Result为长时间运行的操作使用CancellationToken考虑异步流处理连续数据如日志、传感器数据测试异步代码时使用AsyncTestMethods监控异步性能以识别瓶颈保持异步方法链避免混合同步/异步调用