跟着AI学习C# Day26

📅 Day 26:C# 异步编程进阶

✅ 学习目标:

  • 深入理解 async/await 的底层机制;
  • 掌握 ConfigureAwait(false) 的作用与使用场景;
  • 避免异步死锁,理解同步上下文(Synchronization Context);
  • 掌握并行任务处理技巧(Parallel, PLINQ);
  • 使用 ValueTask 替代 Task 提升性能;
  • 构建高性能的异步 API;
  • 编写一个结合多个异步优化技巧的示例程序(如高并发网络爬虫)。

🧠 一、回顾 async/await 基础知识

asyncawait 是什么?

  • async 标记方法为异步方法;
  • await 用于等待异步操作完成而不阻塞线程。
public async Task<string> DownloadAsStringAsync(string url)
{using var client = new HttpClient();return await client.GetStringAsync(url);
}

✅ 状态机原理简述:

编译器会将 async 方法转换为状态机对象(IAsyncStateMachine),自动管理异步流程和上下文切换。


🔁 二、ConfigureAwait(false) 的意义与使用

✅ 默认行为(不加 ConfigureAwait(false)

在 UI 应用中(如 WPF、WinForms),默认会捕获当前的 SynchronizationContext,以便 await 后继续回到 UI 线程执行后续代码。

❗️问题:可能导致死锁!

如果你在 UI 线程调用了 .Result.Wait(),而异步方法又试图回到 UI 线程,就会发生死锁。

✅ 正确做法:库方法应使用 ConfigureAwait(false)

public async Task<string> GetDataAsync()
{string result = await SomeNetworkCallAsync().ConfigureAwait(false);return Process(result);
}

⚠️ 在类库中始终使用 ConfigureAwait(false),除非你明确需要返回到特定上下文(如 UI)。


💀 三、避免异步死锁

❌ 错误写法(UI 线程中):

var result = GetDataAsync().Result;

这会导致主线程被阻塞,并且 await 后想回到这个线程,但该线程正等着结果,导致死锁。

✅ 正确写法:

var result = await GetDataAsync();

或者,在非 UI 场景中使用:

Task.Run(async () => await GetDataAsync()).Wait();

🧩 四、并行任务处理(Parallel & PLINQ)

Parallel.For / Parallel.ForEach

适用于 CPU 密集型任务的并行执行。

Parallel.For(0, 10, i =>
{Console.WriteLine($"处理 {i},线程ID:{Thread.CurrentThread.ManagedThreadId}");
});

✅ PLINQ(Parallel LINQ)

并行查询,适合大数据集合处理:

var numbers = Enumerable.Range(1, 1000000);var result = numbers.AsParallel().Where(n => n % 3 == 0).Sum();Console.WriteLine("总和:" + result);

🧱 五、ValueTask vs Task(.NET Core 2.1+)

Task<T> 的缺点:

每次调用都会分配内存(堆上创建对象),对高频调用或热路径有性能影响。

ValueTask<T> 的优势:

  • 如果结果已知(缓存命中、立即完成),则不分配;
  • 适用于“大多数快速完成”的异步操作。
public ValueTask<int> GetCachedValueAsync()
{if (_cache.HasValue)return new ValueTask<int>(_cache.Value);elsereturn new ValueTask<int>(GetValueFromNetworkAsync());
}

✅ 注意:不能多次 await,否则可能抛出异常。


🔄 六、自定义异步状态机(高级)

你可以通过实现 IValueTaskSource<TResult> 来构建自己的 ValueTask 实现,但这通常只在高性能框架开发中使用。

示例略(复杂度较高,需深入理解状态机机制)。


🧪 七、实战练习:高并发网页爬虫

功能要求:

  • 并发下载多个网页;
  • 使用 HttpClient 异步请求;
  • 避免死锁;
  • 使用 ValueTask 缓存热门页面;
  • 支持配置最大并发数;
  • 输出各页面大小。
示例代码框架:
class WebCrawler
{private readonly HttpClient _client = new();private readonly ConcurrentDictionary<string, string> _cache = new();public async Task<int> CrawlPageAsync(string url){// 使用缓存if (_cache.TryGetValue(url, out var cached))return cached.Length;// 下载网页string content = await _client.GetStringAsync(url).ConfigureAwait(false);_cache.TryAdd(url, content);return content.Length;}public async Task RunAsync(IEnumerable<string> urls){var tasks = urls.Select(url =>Task.Run(async () =>{int length = await CrawlPageAsync(url).ConfigureAwait(false);Console.WriteLine($"{url} 长度:{length}");}));await Task.WhenAll(tasks);}
}

📝 小结

今天你学会了:

  • ConfigureAwait(false) 的作用与使用时机;
  • 如何避免异步死锁;
  • 使用 ParallelPLINQ 实现并行任务;
  • ValueTask 的优势及其适用场景;
  • 自定义异步状态机的基本概念;
  • 编写了一个高并发网页爬虫的异步优化示例。

掌握这些高级异步编程技巧,能显著提升应用程序的响应性、吞吐量和资源利用率,尤其在 Web API、微服务、桌面应用等场景中尤为重要。


🧩 下一步学习方向(Day 27)

明天我们将进入一个新的主题 —— C# 中的反射(Reflection)与元编程,你将学会:

  • 如何在运行时动态加载类型、调用方法;
  • 获取类成员信息(属性、方法、构造函数);
  • 使用 System.Reflection.Emit 创建动态程序集;
  • 反射在依赖注入、序列化、ORM 等框架中的应用;
  • 性能优化技巧(缓存反射结果、使用表达式树代替 Invoke);
  • 编写一个基于反射的通用对象克隆器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/85976.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/85976.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Scrapy | 通过爬取豆瓣Top250电影信息来学习在中间件中应用随机请求头和代理ip

中间件的使用 1.scrapyl中间件的分类和作用1.1 scrapy中间件的分类1.2 scrapy中间的作用:预处理request和response对象2.下载中间件的使用方法:3.定义实现随机User-Agent的下载中间件3.1 实战:爬取豆瓣Top250电影信息3.2 中间件使用实现随机User-Agent4. 代理ip的使用4.1思路…

【深度学习】深度学习入门:从理论到实践的全面指南

深度学习入门&#xff1a;从理论到实践的全面指南 深度学习&#xff1a;开启人工智能新时代的钥匙一、深度学习的广泛应用场景1.1 改变生活的深度学习应用1.2 行业变革案例深度解析案例一&#xff1a;深度学习检测皮肤癌案例二&#xff1a;移动端OCR技术突破案例三&#xff1a;…

MySQL 数据库操作完整指南

MySQL 数据库操作完整指南 目录 创建数据库 连接数据库 创建表 约束详解 插入数据 查询数据 多表联合查询 连接查询 高级查询 更新数据 删除数据 视图详解 存储过程详解 函数详解 触发器 事务处理 索引优化 安全性管理 备份和恢复 性能优化 删除表和数据库 1. 创建数据库 基…

Java面试复习:面向对象编程、Java 8新特性与Spring

Java面试复习&#xff1a;面向对象编程、Java 8新特性与Spring 面向对象编程 概念解析&#xff1a;面向对象编程&#xff08;OOP&#xff09;是将现实世界中的概念抽象为软件模型的编程范式&#xff0c;包括封装、继承和多态。 核心原理&#xff1a; 封装&#xff1a;通过访…

蓝牙数据通讯,实现内网电脑访问外网电脑

最近突然想到了一个可以绕开单位安全管控软件&#xff0c;让单位内部办公电脑连上外网的方法。大概是这个样子&#xff0c;让单位办公电脑与自己的外网电脑进行蓝牙配对&#xff0c;然后用配对成功的蓝牙进行网络数据交互。这里大家可能会想用一下蓝牙的网络共享功能&#xff0…

硬件面经-具身机器人通用技术要求

目录 简介 场景 技术面试 设计知识点 总结 简介 最近机器人特别的火。所以收集了一些关于机器人的面试及要求 场景 目前具身机器人赛道可谓是十分火热,全国大大小小崛起了几十家具身机器人公司,国外比较出名的有波士顿动力,特斯拉等,国内目前比较火的就是宇树,众擎…

DeepSeek生成HTML5图片拼接工具

让DeepSeek生成一个HTML5图片拼接工具&#xff0c;给的提示词如下 提示词(prompt) 帮我生成一个可以将两张图片拼接到一起的程序 支持横向拼接和竖向拼接&#xff0c;可以用html5实现功能吗&#xff1f; DeepSeek大概20秒左右就做好了&#xff0c;而且像这么简单的功能的话也没…

Java面试复习指南:Java基础、面向对象编程与并发编程

Java面试复习指南&#xff1a;Java基础、面向对象编程与并发编程 1. Java基础 概念解析: Java是一种面向对象的编程语言&#xff0c;具有跨平台的特性。 核心原理: JVM负责Java程序的跨平台运行&#xff0c;通过字节码来实现。 高频面试问题: Java如何实现跨平台&#xff…

LeeCode2566替换一个数字后的最大差值

项目场景&#xff1a; 给你一个整数 num 。你知道 Danny Mittal 会偷偷将 0 到 9 中的一个数字 替换 成另一个数字。 请你返回将 num 中 恰好一个 数字进行替换后&#xff0c;得到的最大值和最小值的差为多少。 注意&#xff1a; 当 Danny 将一个数字 d1 替换成另一个数字 …

李宏毅2025《机器学习》第三讲-AI的脑科学

在之前的课程中探讨了如何利用大模型构建AI Agent,本科将暂时放下应用层面的探索,拿起“手术刀”和“显微镜”,深入剖析LLM的“大脑”,带您踏上一场“AI脑神经科学”的旅程。课程不讨论模型的训练过程,而是假设我们拥有一个已经训练好的、功能完备的LLM。我们的目标是:理…

CVPR 2025 | 微米级光影CT精度!复旦腾讯优图开源Real-IAD D³数据集

【导读】 本文介绍了复旦联合腾讯优图发布高精度多模态数据集Real-IAD D&#xff0c;并基于此数据集提出了一种创新的多模态融合检测方法&#xff0c;数据集已被CVPR 2025收录&#xff0c;并开源。>>更多资讯可加入CV技术群获取了解哦~ 目录 一、Real-IAD D的创新之处…

解决mysql左连接加where就不会保留左表中的全部数据的问题

在SQL中使用MySQL的LEFT JOIN操作时,如果加入了WHERE条件,确实会影响结果集的完整性,特别是如果你在WHERE条件中使用了JOIN的另一张表中的字段作为过滤条件。这是因为当你在WHERE子句中加入了对JOIN另一张表的过滤条件时,实际上你是在执行一个INNER JOIN(内连接)而非LEFT…

算法与数据结构:动态规划DP

文章目录 动态规划算法全面解析一、核心思想与基本概念二、动态规划与其他算法的区别三、动态规划的解题步骤四、经典案例解析1. **斐波那契数列&#xff08;Fibonacci&#xff09;**2. **0-1背包问题&#xff08;0-1 Knapsack&#xff09;**3. **最长公共子序列&#xff08;LC…

Coilcraft电感上的横线是什么意思?电感有方向么?

通常我们会认为电容、电感、电阻这几类无源器件没有方向性&#xff0c;在布局和贴片时可以任意方向放置&#xff0c;也不会在PCB上增加丝印标识说明其方向。与此相互印证的是&#xff0c;电容表面无丝印&#xff0c;无法识别方向&#xff1b;电阻表面一般只有包含阻值大小的数字…

通过Docker挂载nginx并修改页面

1&#xff1a;通过docker创建nginx&#xff1a; 首先关闭原来的Docker&#xff08;防止端口号冲突&#xff09; sudo nginx -s stop 直接启动 Nginx 进程 sudo nginx 启动nginx&#xff1a; docker run -di --namemynginx -p 80:80 nginx cd /etc/nginx docker run -d …

力扣1124. 表现良好的最长时间段

这一题我看到数据范围是10^4&#xff0c;暗自窃喜能用双重循环&#xff0c;看题目是典型的前缀和哈希。不过需要一个转换将大于8小时的转化为1&#xff0c;其他都为-1&#xff0c;方便计算&#xff0c;之前的题目中也有这种方法。 那这样就简单了 class Solution { public:int…

EDA2算法速通(编者崩溃版)

这个内容是用来回忆一下EDA2涉及的算法和解题的主要步骤&#xff1a; 有疑问或发现错误可以私信来讨论 高级综合概述 柏拉图优化&#xff1a;这个是来判断是否有哪些节点能完全被其他节点优化掉。比如&#xff08;1,2&#xff09;这个节点就可以完全优化&#xff08;3,4&…

雷池waf配置第三方登录-钉钉配置详细教程

雷池waf配置第三方登录-钉钉配置详细教程 前往钉钉开放平台https://open.dingtalk.com/ 选择一个登录方式登录钉钉开放平台 选择一个自己所管理的组织 登录成功后点击我的后台 选择应用开发 在钉钉应用下点击创建应用 填写应用名称和应用描述后点击保存 点击网页…

神经网络中的均方误差(Mean Squared Error)详解

引言 在机器学习和神经网络领域&#xff0c;损失函数&#xff08;Loss Function&#xff09;是衡量模型预测值与真实值之间差异的关键指标。均方误差&#xff08;Mean Squared Error, MSE&#xff09;作为一种经典的损失函数&#xff0c;因其简单性、可解释性和数学上的优良性…

day036-lsyncd实时同步服务与网站存储架构

文章目录 1. 实时同步工具2. lsyncd 实时同步服务2.1 环境准备2.2 rsync准备2.2.1 服务端检查2.2.2 客户端检查2.2.3 备份测试 2.3 配置lsyncd2.3.1 安装软件2.3.2 编写配置文件 2.4 测试 3. 案例-网站存储架构3.1 rsync服务配置3.1.1 服务端配置3.1.2 客户端配置 3.2 lsyncd服…