0

0

c# 编写高并发代码时,如何平衡性能和可读性

幻夢星雲

幻夢星雲

发布时间:2025-12-31 10:23:28

|

173人浏览过

|

来源于php中文网

原创

用 ValueTask 替代 Task 可避免堆分配,但仅限同步完成路径且不跨 await 边界重用;错误使用会抛 InvalidOperationException;应优先用于高频内部方法,公共 API 慎用,需复用时转 Task,禁用 ConfigureAwait(false)。

c# 编写高并发代码时,如何平衡性能和可读性

ValueTask 替代 Task 时要注意同步完成路径

同步返回的异步方法(比如缓存命中、参数校验失败)用 ValueTask 能避免堆分配,但前提是不跨 await 边界重用或暴露给外部。常见错误是把 ValueTask 存进字段、传给非 await 上下文(如 ContinueWith),或在未 await 前多次 await —— 这会抛 InvalidOperationException: "ValueTask may only be awaited once"

实操建议:

  • 只在 hot path(如高频 API 入口、内存缓存读取)中对确定「大概率同步完成」的方法用 ValueTask
  • 避免在公共 API 返回 ValueTask,除非你完全控制调用方行为;内部方法可放宽
  • 若需复用或延迟 await,先转成 Task
    var task = valueTask.AsTask();
  • 别用 ValueTask.ConfigureAwait(false) —— 它不存在,必须先转 Task

异步流处理优先选 IAsyncEnumerable,但别在循环里开新 async 方法

IAsyncEnumerable 是 C# 8+ 处理高并发数据流(如分页查库、实时日志推送)的自然选择,但它本身不解决并发度控制。常见陷阱是写成这样:

await foreach (var item in GetItemsAsync()) // 每次 yield 都可能触发一次 DB 查询
{
    await ProcessItemAsync(item); // 串行执行,吞吐掉一半
}

正确做法是用 Task.WhenAll 控制并发批次,同时保持流式内存友好:

  • BufferBlock(来自 System.Threading.Tasks.Dataflow)做生产者-消费者解耦
  • 限制并行度:用 Parallel.ForEachAsync(.NET 6+)并设 MaxDegreeOfParallelism
  • 若仍用 await foreach,提前批量化:var batch = items.Take(100).ToList(),再 Task.WhenAll(batch.Select(ProcessItemAsync))

锁不是唯一瓶颈,ConcurrentDictionaryImmutableArray 往往更轻量

高并发下盲目加 lockMonitor 容易成为争用热点,尤其在短临界区(如更新计数器、查缓存)。ConcurrentDictionaryGetOrAddAddOrUpdate无锁设计,比手动 lock + Dictionary 快 3–5 倍(实测 .NET 6+)。

BgSub
BgSub

免费的AI图片背景去除工具

下载

但要注意:

  • ConcurrentDictionary 的枚举不是线程安全快照,遍历时可能漏项或重复;需要完整快照就用 ToArray()
  • 高频小对象拼接(如日志上下文构建)用 ImmutableArray.BuilderList + lock 更省 GC
  • 纯读多写少场景,考虑 Lazy + ConcurrentDictionary 组合,避免重复初始化

可读性妥协点要显式标注,比如用 [SkipLocalsInit] 或内联 Span

极致性能优化(如零分配序列化、Socket 缓冲区复用)必然牺牲可读性。这时别藏技巧,用编译器特性或注释明确意图:

  • [SkipLocalsInit] 省掉上数组初始化开销,但必须确保所有分支都赋值,否则行为未定义
  • 字符串解析优先用 ReadOnlySpan + Span,避免 Encoding.UTF8.GetBytes(str) 分配;但只在 hot path 用,普通逻辑保持 string
  • 在方法名或 XML 注释里写清权衡:“// ⚠️ 零分配,但要求 input.Length

最难的不是写出高性能代码,而是让半年后的自己或同事一眼看出哪行是“为吞吐让步”,哪行是“真不能动”。可读性和性能冲突时,边界一定要划清楚——模糊地带最容易出偶发超时或内存泄漏。

相关文章

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

312

2023.08.02

php中foreach用法
php中foreach用法

本专题整合了php中foreach用法的相关介绍,阅读专题下面的文章了解更多详细教程。

37

2025.12.04

pdf怎么转换成xml格式
pdf怎么转换成xml格式

将 pdf 转换为 xml 的方法:1. 使用在线转换器;2. 使用桌面软件(如 adobe acrobat、itext);3. 使用命令行工具(如 pdftoxml)。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1851

2024.04.01

xml怎么变成word
xml怎么变成word

步骤:1. 导入 xml 文件;2. 选择 xml 结构;3. 映射 xml 元素到 word 元素;4. 生成 word 文档。提示:确保 xml 文件结构良好,并预览 word 文档以验证转换是否成功。想了解更多xml的相关内容,可以阅读本专题下面的文章。

2080

2024.08.01

xml是什么格式的文件
xml是什么格式的文件

xml是一种纯文本格式的文件。xml指的是可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。想了解更多相关的内容,可阅读本专题下面的相关文章。

919

2024.11.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

248

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

205

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1435

2023.10.24

桌面文件位置介绍
桌面文件位置介绍

本专题整合了桌面文件相关教程,阅读专题下面的文章了解更多内容。

0

2025.12.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 0.9万人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号