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

C# 高并发处理方式

高并发本质是系统在单位时间内处理大量并行请求的能力。

在C#中处理这个问题需要分层解决:首先是架构层面,比如是否采用分布式;然后是语言特性层面,比如异步编程;最后是基础设施层面,比如数据库优化。

目录

1. 异步编程(async/await)

核心思想:

优势:

C# 实现:

2. 分布式架构

(1) 消息队列(削峰填谷)

(2) 分布式缓存

3. 数据库优化

4. 使用锁(lock)和互斥量(Mutex)

乐观锁 

Redis分布式锁

原理

适用场景

5. 使用线程池(ThreadPool)和Task.Run

典型误区

6. 并发集合 (System.Collections.Concurrent)

核心思想:

常用类:

1. 异步编程(async/await)

核心思想:

避免阻塞线程。当一个操作(如 I/O - 文件读写、网络请求、数据库查询)需要等待外部资源时,释放当前线程去处理其他请求,待操作完成后再由线程池分配线程继续执行。

优势:

显著提高线程池线程的利用率(一个线程可处理多个请求),用更少的线程服务更多的并发请求,减少线程上下文切换开销,提高系统吞吐量和响应能力。

C# 实现:

 使用 async 关键字标记异步方法,在需要等待的操作前使用 await 关键字。

public async Task<ActionResult> GetData()
{var data = await _dbContext.Data.ToListAsync(); // 异步数据库操作return Ok(data);
}
  • 关键点

    • 所有 I/O 操作(数据库、网络、文件)必须异步

    • 避免 Task.Wait() 或 Task.Result(会导致死锁)

2. 分布式架构

(1) 消息队列(削峰填谷)

  • 核心思想: 将耗时的、非实时的操作(如发送邮件、生成报告、复杂数据处理)异步化。请求到达后,将任务信息放入消息队列(如 RabbitMQ, Azure Service Bus, Kafka, Amazon SQS),立即返回响应。后台有专门的“消费者”进程从队列中取出消息并处理。

  • 优势:

    • 削峰填谷: 突发的高流量可以被队列缓冲,消费者按自身能力消费,避免后端服务瞬时过载崩溃。

    • 解耦: 生产者和消费者完全解耦,互不影响,提高系统可靠性和可维护性。

    • 异步处理: 释放 Web 服务器线程,使其专注于处理用户请求。

    • 重试机制: 消息队列通常支持消息传递失败后的重试。

// 使用 RabbitMQ.Client 发送
using var channel = _connection.CreateModel();
channel.QueueDeclare("orders");
var body = Encoding.UTF8.GetBytes(orderJson);
channel.BasicPublish("", "orders", body); // 异步解耦
  • 推荐工具RabbitMQ、Kafka、Azure Service Bus

(2) 分布式缓存

  • 核心思想: 将频繁读取但不经常变化的数据(如配置、热门商品信息、会话状态)存储在独立于应用服务器、高性能的内存缓存服务(如 Redis, Memcached中。

  • 优势:

  • 极大减少对后端数据库(通常是性能瓶颈)的访问次数。

  • 数据存储在内存中,访问速度极快。

  • 支持分布式部署,多个应用实例共享同一缓存,保证数据一致性。

  • 提高应用的可扩展性(水平扩展应用服务器时,缓存层通常更容易扩展)

  • 推荐工具Redis, Memcached

// 使用 StackExchange.Redis
IDatabase cache = Connection.GetDatabase();
await cache.StringSetAsync("key", "value", TimeSpan.FromMinutes(10));
string value = await cache.StringGetAsync("key");

3. 数据库优化

  • 连接池: ADO.NET 和 ORM(如 EF Core)默认管理数据库连接池。确保配置合理的 MinPoolSize 和 MaxPoolSize

  • 异步数据库操作 务必使用 ORM 或 ADO.NET 提供的异步方法(如 ToListAsync()SaveChangesAsync()ExecuteReaderAsync())来执行数据库查询和命令。

  • 优化查询:

    • 使用索引避免全表扫描。

    • 只查询需要的字段(Select)。

    • 避免 N+1 查询问题(EF Core 中注意使用 Include 或投影)。

    • 合理设计数据模型。

    • 考虑读写分离、分库分表(在数据量极大时)。

  • NoSQL 考虑: 对于某些特定场景(如文档存储、键值对、宽列存储、图数据库),NoSQL 数据库(如 MongoDB, Cassandra, Cosmos DB)可能比关系型数据库(如 SQL Server, PostgreSQL)更适合高并发读写和水平扩展。

4. 使用锁(lock)和互斥量(Mutex

  • 核心思想: 当多个线程需要访问共享资源(如静态变量、单例实例、文件句柄)时,必须协调它们的访问,防止数据损坏或状态不一致。

  • 常用机制:lock 语句: 最常用,基于 Monitor 类,提供互斥锁。

虽然锁在高并发场景下可能会引起性能瓶颈,但在某些情况下仍然需要使用。确保只在必要时使用,并尽可能减少锁定范围。

private object lockObject = new object();
public void ProcessData(int data)
{lock (lockObject){// 执行需要同步的代码块}
}

乐观锁和Redis分布式锁都是处理高并发场景的核心方案

乐观锁 

乐观锁 通过版本号(Version)或时间戳(Timestamp)实现“无锁”并发控制:

  1. 读阶段:读取数据时记录当前版本号。

  2. 写阶段:提交更新前校验版本号是否未变化,若变化则重试或失败。

  3. 典型实现包括:

    • 数据库乐观锁:通过SQL语句(如UPDATE ... WHERE version=old_version)。

    • Redis的WATCH/MULTI:监视Key变化,事务中执行CAS操作

Redis分布式锁
原理

基于Redis的原子操作(如SET key value NX PX)实现互斥访问:

  • 加锁:通过SETNX设置唯一值并附加超时时间。

  • 续期:Redisson的Watchdog线程自动延长锁有效期。

  • 释放:校验持有者身份后删除Key。

适用场景
  • 低冲突场景:如读多写少的业务(商品浏览、配置读取)。

  • 突发流量:秒杀系统中库存扣减(配合重试机制)。

  • 需高吞吐:避免锁竞争,提升并发能力

乐观锁和Redis分布式锁是处理高并发的互补方案而非互斥:

  • ✅ 乐观锁:轻量、高吞吐,适合低冲突场景,需防范ABA问题。

  • ✅ Redis分布式锁:强一致、易用,需优化主从容错与锁粒度。
    实际系统中常组合使用(如Redis锁拦截请求+数据库乐观锁保证最终一致)

Monitor 类: lock 的底层实现,提供更细粒度控制(如 TryEnterWaitPulse)。

Mutex: 进程间或跨 AppDomain 的互斥锁,重量级。

 //当前电脑只能启动一个WCS程序using (System.Threading.Mutex m = new System.Threading.Mutex(true, AppConfig.Instance.GetConfig("主界面名称"), out Started)){if (Started){if (DbManagerBase.Instance.GetDbTime() == false){MessageBox.Show("数据库连接失败,请检查原因!");}else{Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Application.Run(new FrmMain());}}else{LibManager.WriteLog("WCS程序启动失败,与运行中WCS程序的主界面名称重复", RecordLogTypeEnum.Error.ToString(), "");MessageBox.Show("当前WCS程序已启动!");}}

关键原则:

  • 最小化锁范围: 只在绝对必要的地方加锁,并尽快释放锁。

  • 避免锁嵌套: 容易导致死锁。

  • 锁粒度: 根据共享资源的范围选择合适的锁(细粒度锁通常并发性更好)。

  • 优先使用并发集合: 在可能的情况下,用 ConcurrentDictionary 等代替自己用锁实现的集合

5. 使用线程池(ThreadPool)和Task.Run

对于需要大量并发线程的场景,可以使用Task.Run来启动一个新任务到线程池中。

.NET 运行时维护一个预先创建的线程池,用于执行后台任务和处理异步回调。

这比手动创建和销毁线程更高效。

Task[] tasks = new Task[10];
for (int i = 0; i < 10; i++)
{tasks[i] = Task.Run(() => DoWork());
}
await Task.WhenAll(tasks);

典型误区

  1. 过度使用 Task.Run:I/O 操作直接用 async 而非封装线程

  2. 全局静态锁:导致无谓的线程阻塞

  3. 同步调用异步方法GetAwaiter().GetResult() 引发死锁

  4. 忽略连接池配置:数据库连接成为瓶颈

💡 黄金法则
异步化所有 I/O 路径 + 避免共享状态 + 队列解耦
通过负载测试(如 JMeter/LoadRunner)持续验证系统极限。

6. 并发集合 (System.Collections.Concurrent)

  • 核心思想:
  •  提供线程安全的集合类,允许多个线程安全地添加、移除或访问集合中的元素,而无需开发者手动加锁。

  • 常用类:
    • ConcurrentQueue<T>: 先进先出 (FIFO) 队列。

    • ConcurrentStack<T>: 后进先出 (LIFO) 栈。

    • ConcurrentDictionary<TKey, TValue>: 键值对字典。

    • ConcurrentBag<T>: 无序集合,适用于对象池等场景。

    • BlockingCollection<T>: 提供阻塞和限制功能的集合,常用于生产者-消费者模式。

    • 优势: 简化多线程编程,避免锁竞争(内部使用高效的锁或无锁技术),提高并发访问性能。

    • 示例: 使用 ConcurrentQueue 实现简单的生产者-消费者。

using System.Collections.Concurrent;private static readonly ConcurrentDictionary<Type, string> assemblyQualifiedNameCache = new ConcurrentDictionary<Type, string>();

http://www.lryc.cn/news/621334.html

相关文章:

  • 算法题Day1
  • torchvision中数据集的使用与DataLoader 小土堆pytorch记录
  • # Vue 列表渲染详解
  • VLMs开发——基于Qwen2.5-VL 实现视觉语言模型在目标检测中的层级结构与实现方法
  • RxJava Android 创建操作符实战:从数据源到Observable
  • 中久数创——笔试题
  • PiscTrace基于YOLO追踪算法的物体速度检测系统详解
  • 2025.8.24复习总结
  • React.memo、useMemo 和 React.PureComponent的区别
  • 基于场景的无人驾驶叉车分类研究:应用场景与技术选型分析
  • springboot myabtis返回list对象集合,对象的一个属性为List对象
  • 飞算 JavaAI 真是 yyds
  • 一周学会Matplotlib3 Python 数据可视化-绘制面积图(Area)
  • [C++] Git 使用教程(从入门到常用操作)
  • TDengine IDMP 基本功能(6. 无问智推)
  • TDengine IDMP 基本功能(7. 智能问数)
  • C++11新特性深度解析
  • 【CF】Day127——杂题 (数论 gcd | 数论 gcd | 博弈论 | 二分图判断 | 贪心 + 暴力 / 二分答案 | 数论 gcd + 动态规划)
  • OSG+Qt —— 笔记1 - Qt窗口加载模型(附源码)
  • Mybatis 源码解读-SqlSession 会话源码和Executor SQL操作执行器源码
  • 《Python函数:从入门到精通,一文掌握函数编程精髓》
  • Transformer网络结构解析
  • 《嵌入式 C 语言编码规范与工程实践个人笔记》参考华为C语言规范标准
  • CNN - 卷积层
  • GaussDB数据库架构师修炼(十六) 如何选择磁盘
  • 《算法导论》第 24 章 - 单源最短路径
  • 20250814 最小生成树总结
  • Java 大视界 -- Java 大数据机器学习模型在金融欺诈检测与防范策略制定中的应用(397)
  • 【Demo】AI-ModelScope/bert-base-uncase 模型训练及使用
  • 市面上有没有可以导入自有AI算法模型的低空平台?