C# 使用 Queue 配合后台线程处理高并发请求
在高并发场景中,直接同步处理大量请求容易导致界面卡顿或服务器过载。本文通过 C# 中的 Queue 类结合后台线程,展示如何实现简单的生产者-消费者模式,将快速入队的请求交由后台异步处理,从而提升系统响应能力。
并发问题的典型场景
假设有一个抢购接口,库存仅有 5 件商品,但同一时刻有 100 个用户发起请求。若采用传统的同步处理方式,所有请求并行执行不仅会耗尽服务器资源,还可能导致数据不一致或服务不可用。借鉴超市结账排队的逻辑,我们可以将这些请求按时间顺序放入一个“队列”中,由后台工作人员(线程)依次处理,这就是解决简单并发问题的核心思路。
准备工作:定义数据结构与辅助类
第1步:定义任务数据模型
首先需要定义一个结构体或类来封装需要处理的数据。例如,在处理文章发布时携带的媒体信息:
public class QueueInfo
{
public string medias { get; set; }
public string proids { get; set; }
public string host { get; set; }
public string userid { get; set; }
public string feedid { get; set; }
}
第2步:创建单例帮助类 BusinessInfoHelper
创建一个单例类来管理队列和后台线程。该类包含核心的入队方法、启动方法以及后台轮询处理方法。
第3步:实现队列管理与线程逻辑
在 BusinessInfoHelper.cs 中,使用 Queue<QueueInfo> 存储任务,并通过私有构造函数保证单例模式。关键代码如下:
public class BusinessInfoHelper
{
// 单例模式
public readonly static BusinessInfoHelper Instance = new BusinessInfoHelper();
private BusinessInfoHelper() { }
// 任务队列
private Queue<QueueInfo> ListQueue = new Queue<QueueInfo>();
/// <summary>
/// 入列操作(生产端调用)
/// </summary>
public void AddQueue(string medias, string proids, string host, string userid, string feedid)
{
var queueinfo = new QueueInfo
{
medias = medias,
proids = prooids,
host = host,
userid = userid,
feedid = feedid
};
ListQueue.Enqueue(queueinfo);
}
/// <summary>
/// 启动后台处理线程
/// </summary>
public void Start()
{
Thread thread = new Thread(threadStart);
thread.IsBackground = true; // 设为后台线程,随主程序退出而终止
thread.Start();
}
/// <summary>
/// 后台线程执行入口
/// </summary>
private void threadStart()
{
while (true)
{
if (ListQueue.Count > 0)
{
try
{
ScanQueue();
}
catch (Exception ex)
{
// 记录日志
// LO_LogInfo.WLlog(ex.ToString());
}
}
else
{
// 队列为空时适当休眠,避免 CPU 空转
Thread.Sleep(3000);
}
}
}
/// <summary>
/// 扫描并处理队列中的任务
/// </summary>
private void ScanQueue()
{
// 注意:实际生产中建议加锁防止多线程并发修改集合,此处为简化示例
while (ListQueue.Count > 0)
{
try
{
// 出列操作(消费端)
var queueinfo = ListQueue.Dequeue();
// 在此处编写具体的业务处理逻辑
// ProcessTask(queueinfo);
}
catch (Exception ex)
{
throw;
}
}
}
}
实际操作顺序
第4步:初始化并启动服务
为了确保队列服务在应用程序启动时即运行,需要在 Global.asax 文件的 Application_Start 事件中调用启动方法:
// Global.asax.cs
protected void Application_Start()
{
// ...其他注册代码...
// 启动发布优质媒体程序(后台队列处理)
MyNameSpace.BusinessInfoHelper.Instance.Start();
}
第5步:接入业务逻辑
在前端控制器或 API 接口中,当接收到发布请求时,不再直接执行耗时操作,而是将其加入队列:
// 业务控制器中
public ActionResult PublishArticle(string medias, string proids, string host, string userid, string feedid)
{
// 快速入队,立即返回响应,不阻塞前端
BusinessInfoHelper.Instance.AddQueue(medias, prooids, host, userid, feedid);
return Json(new { success = true, message = "已加入处理队列" });
}
进阶:使用 Lock 确保线程安全
上述基础方案在多并发写入队列时可能存在竞态条件。如果需要更严格的线程安全控制,或者在处理过程中需要锁定特定资源(如数据库连接),可以使用 lock 关键字。
第6步:定义全局锁对象
在类中定义一个静态只读对象作为锁标志:
private static readonly object lockObject = new object();
第7步:在关键代码块应用锁定
对可能引起冲突的代码段进行保护:
lock(lockObject)
{
// 临界区代码
// 例如:更新共享状态、写入文件等
}
完成判断
- 功能验证:提交多个发布请求后,前端能迅速收到反馈,而后台日志显示任务被逐个处理。
- 稳定性测试:在高频率请求下,观察内存占用是否平稳,后台线程是否持续运行且无异常崩溃。
- 线程安全:通过引入
lock机制,确保对共享资源的访问是原子性的,避免数据竞争。
简要总结
通过使用 Queue 和后台线程,我们构建了一个简易的生产者-消费者模型。这种方法有效地将耗时的业务逻辑从主请求链路中剥离,提升了系统的吞吐量和响应速度。同时,辅以 lock 机制可以进一步增强代码的健壮性。以上就是 C# 使用队列(Queue)解决简单的并发问题的详细内容,更多关于 C#并发处理与队列优化的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













