在C#中实现抢票功能,推荐使用策略模式(Strategy Pattern) 结合队列机制(Queue),以下是详细分析和代码示例:
设计模式选择依据
-
策略模式(核心)
- 动态切换不同抢票算法(如随机分配、优先级队列、时间片轮转)
- 解耦业务逻辑与具体实现
- 公式表示:抢票服务=策略接口⊕具体算法 \text{抢票服务} = \text{策略接口} \oplus \text{具体算法} 抢票服务=策略接口⊕具体算法
-
队列机制(必备辅助)
- 解决高并发场景下的资源竞争问题
- 通过消息队列缓冲请求(如RabbitMQ或Redis Streams)
- 避免直接操作数据库导致的锁冲突
伪代码实现
// 1. 策略接口
public interface ITicketStrategy
{
bool GrabTicket(User user, Ticket ticket);
}
// 2. 具体策略实现
public class RandomStrategy : ITicketStrategy
{
public bool GrabTicket(User user, Ticket ticket)
{
// 随机分配算法
var rnd = new Random();
return rnd.Next(0, 100) > 50; // 50%成功率
}
}
public class PriorityStrategy : ITicketStrategy
{
public bool GrabTicket(User user, Ticket ticket)
{
// VIP用户优先逻辑
return user.IsVip ? true : new Random().Next(0, 100) > 80;
}
}
// 3. 上下文控制器(核心调度)
public class TicketGrabber
{
private ITicketStrategy _strategy;
private readonly Queue<GrabRequest> _requestQueue = new();
public void SetStrategy(ITicketStrategy strategy) => _strategy = strategy;
public void EnqueueRequest(User user, Ticket ticket)
{
_requestQueue.Enqueue(new GrabRequest(user, ticket));
}
public void ProcessQueue()
{
while (_requestQueue.Count > 0)
{
var request = _requestQueue.Dequeue();
var result = _strategy.GrabTicket(request.User, request.Ticket);
NotifyUser(request.User, result);
}
}
}
// 4. 使用示例
var grabber = new TicketGrabber();
grabber.SetStrategy(new PriorityStrategy()); // 动态切换策略
// 模拟100个用户请求
Parallel.For(0, 100, i =>
{
grabber.EnqueueRequest(new User($"User{i}", isVip: i % 10 == 0),
new Ticket("Concert-001"));
});
grabber.ProcessQueue();
关键优化点
-
并发控制
- 使用
ConcurrentQueue替代普通队列 - 通过
SemaphoreSlim限制并发处理数
- 使用
-
持久化保障
// 结合数据库事务 using (var transaction = db.BeginTransaction()) { if (_strategy.GrabTicket(user, ticket)) { db.SaveOrder(user, ticket); transaction.Commit(); } } -
熔断机制
当库存低于阈值时切换策略:if (ticket.Stock < 10) grabber.SetStrategy(new HighPressureStrategy()); // 高压策略
其他备选模式
- 观察者模式(Observer):用于实时通知抢票结果
- 代理模式(Proxy):在客户端和服务端之间增加缓存层
- 状态模式(State):根据系统负载动态调整抢票状态
总结:在C#抢票系统中,策略模式+队列是核心组合,能有效平衡高并发和业务灵活性。实际部署时需配合Redis缓存、数据库分片和负载均衡,建议使用Actor模型(如Akka.NET)处理超大规模请求。

被折叠的 条评论
为什么被折叠?



