当前位置: 首页 > news >正文

c# 异步编程详细说明及实践

在C#中,异步编程是一种至关重要的技术,它能显著提升应用程序的响应能力和资源利用率。下面我将详细解释其核心概念、使用方法和最佳实践

C# 异步编程详解

1. 异步编程的核心概念
异步编程是一种允许程序在等待耗时操作(如I/O或计算)完成的同时,不阻塞主线程的执行模型。这对于需要保持用户界面响应性或提高服务器应用吞吐量的场景尤为重要

同步执行异步执行
同步操作会阻塞当前线程直到任务完成,导致资源浪费和界面冻结异步操作在等待结果时不阻塞线程,使线程可以处理其他任务

核心构建块:
Task 和 Task:表示异步操作的对象,是异步编程的基础
async/await关键字:C#语言级别的异步支持,使异步代码编写更加直观

2. async和await关键字详解
2.1 声明异步方法
使用async修饰符声明方法,表明该方法包含异步操作:

public async Task<int> GetDataAsync()
{// 异步操作
}

异步方法通常返回Task(无返回值)、Task(有返回值)或void(仅用于事件处理程序)

2.2 await表达式
await关键字挂起当前方法的执行,直到等待的任务完成,同时将控制权返回给调用方:

public async Task<string> DownloadContentAsync(string url)
{using (var client = new HttpClient()){return await client.GetStringAsync(url);}
}

当await的任务完成后,方法会从暂停处恢复执行。

3. 区分I/O绑定和CPU绑定任务
3.1 I/O绑定任务
这类任务涉及输入/输出操作,如网络请求、文件读写或数据库访问。它们不需要专用线程,在等待硬件响应时自然释放线程资源。
最佳实践:直接使用await而不包装在Task.Run中:

// I/O绑定示例
public async Task<string> ReadFileAsync(string filePath)
{string content = await File.ReadAllTextAsync(filePath);return content;
}

3.2 CPU绑定任务
这类任务需要进行大量计算,如图像处理、复杂算法等。它们需要专用线程执行计算
最佳实践:使用Task.Run将工作卸载到线程池线程:

// CPU绑定示例
public async Task<int> PerformExpensiveCalculationAsync()
{var result = await Task.Run(() => {// 耗时计算int sum = 0;for (int i = 0; i < 1000000; i++) {sum += i;}return sum;});return result;
}

4. 高级异步模式与技术
4.1 等待多个任务
Task API提供了高效处理多个异步操作的方法:
Task.WhenAll:等待所有任务完成

public async Task<string[]> DownloadAllAsync(string[] urls)
{var downloadTasks = urls.Select(url => DownloadContentAsync(url)).ToArray();return await Task.WhenAll(downloadTasks);
}

Task.WhenAny:等待任一任务完成

var firstCompletedTask = await Task.WhenAny(tasks);
var result = await firstCompletedTask;

4.2 错误处理
异步方法中的异常会被封装在Task对象中,可以使用try/catch块捕获:

public async Task<int> SafeGetDataAsync()
{try{return await GetDataAsync();}catch (HttpRequestException ex){// 处理特定异常Console.WriteLine($"网络请求错误: {ex.Message}");return -1;}catch (Exception ex){// 处理其他异常Console.WriteLine($"发生错误: {ex.Message}");return -1;}
}

对于多个任务,异常处理需要特别注意:

try
{await Task.WhenAll(task1, task2);
}
catch (Exception ex)
{// 即使多个任务失败,也只会捕获第一个异常
}// 获取所有任务的异常信息
var allTasks = Task.WhenAll(task1, task2);
try
{await allTasks;
}
catch
{if (allTasks.Exception != null){foreach (var exception in allTasks.Exception.InnerExceptions){// 处理每个异常}}
}

4.3 取消异步操作
使用CancellationToken实现异步操作的取消:

public async Task<int> DownloadWithCancellationAsync(string url, CancellationToken cancellationToken = default)
{using (var client = new HttpClient()){await Task.Delay(1000, cancellationToken); // 可取消的延迟var response = await client.GetAsync(url, cancellationToken);return await response.Content.ReadAsStringAsync();}
}// 使用示例
var cts = new CancellationTokenSource();
cts.CancelAfter(5000); // 5秒后自动取消try
{var result = await DownloadWithCancellationAsync("http://example.com", cts.Token);
}
catch (OperationCanceledException)
{Console.WriteLine("操作已被取消");
}

异步编程最佳实践

1.避免async void:除了事件处理程序外,始终返回Task或Task,因为async void方法的异常无法捕获
2.使用ConfigureAwait(false):在非UI代码中使用ConfigureAwait(false)可以避免死锁并提高性能:
var result = await SomeAsyncMethod().ConfigureAwait(false);
3.遵循命名约定:异步方法名应以"Async"为后缀
4.避免阻塞异步代码:不要使用.Result或.Wait(),这可能导致死锁
5.考虑使用ValueTask:在性能关键路径中,当方法可能同步完成时,使用ValueTask可以减少内存分配
6.编写无状态代码:避免依赖全局状态,使代码更易于测试和维护

实际应用示例

并发处理多个请求

public async Task<string[]> ProcessMultipleUrlsAsync(string[] urls)
{var client = new HttpClient();var tasks = urls.Select(async url =>{var response = await client.GetAsync(url);return await response.Content.ReadAsStringAsync();}).ToArray();return await Task.WhenAll(tasks);
}

带进度报告的异步操作

public async Task<int> ProcessDataAsync(IProgress<int> progress = null)
{int totalItems = 100;for (int i = 0; i < totalItems; i++){await Task.Delay(100); // 模拟工作progress?.Report((i + 1) * 100 / totalItems);}return totalItems;
}

掌握C#异步编程需要理解其核心概念、区分不同任务类型,并遵循最佳实践。通过合理应用async/await,可以编写出高效、响应性好的应用程序

http://www.dtcms.com/a/604974.html

相关文章:

  • 系统架构设计师论文分享-论设计模式的应用
  • 漫谈我与C++
  • HarmonyOS 6.0 服务卡片实战:把「轻食刻」装进桌面,让轻断食一眼可控
  • 建设网站用什么技术网站的基本类型
  • 罗湖附近公司做网站建设哪家效益快阜阳微网站建设多少钱
  • C++-Qt-音视频-基础问题01
  • [Linux]学习笔记系列 -- [kernel]notifier
  • Blender学习笔记(0) -- 思维导图框架
  • 云手机 服务器网络安全
  • 服务器BMC开发视角:解析CPU管理的两大核心接口PECI与APML
  • Linux 服务器安装 dstat 监控插件
  • 与实验室服务器互相ping
  • C++ 二叉搜索树的模拟实现(key结构的非递归和key_value结构的非递归的实现)
  • dw制作简单网站如何推广新品
  • SUSE Linux Enterprise Server 15 SP4安装步骤
  • 红帽企业 Linux 9 启动过程详解:从按下电源到登录提示符
  • 合肥建设厅网站建设一个一般网站需要多少钱
  • 麻省理工学院未来研发更高温超导体打开了新路径
  • Android studio修改app 桌面logo和名称
  • 【MCU控制 初级手札】2.1 电学基础知识 【电学基础】
  • C#1113变量类型
  • RabbitMq消费消息遇到的坑
  • SAP FICO应付账款账龄分析表
  • Pinia Store 生命周期与状态持久性详解
  • 大数据时代时序数据库选型指南:为何Apache IoTDB是最优解
  • 做网站的一个专题在线上传图片生成链接
  • 图论专题(三):“可达性”的探索——DFS/BFS 勇闯「钥匙和房间」
  • 图论专题(一):Hello, Graph! 掌握“建图”与“遍历”的灵魂
  • 做彩票网站能挣到钱吗中国最好的购物平台
  • 南京做网站群的公司岳西县住房和城乡建设局网站