ConcurrentQueue 和 Queue+lock 哪个更快?看场景,不是看名字
结论很直接:**在典型多线程生产者-消费者场景下(比如多个 socket 接收线程入队 + 多个工作线程出队),ConcurrentQueue 通常比手动用
lock包裹
Queue<t></t>更快,尤其连接数 ≥ 数千时**。但这个“更快”有前提——你没滥用
Count,也没在单线程里硬套它。
为什么 ConcurrentQueue 在高并发下更胜一筹?
核心是「无锁」不等于「没开销」,而是把竞争从「阻塞等待锁」换成了「快速重试 + CAS 原子操作」。当多个线程同时
Enqueue或
TryDequeue时:
Queue<t></t>+
lock:所有争抢锁的线程会进入阻塞态,触发上下文切换,CPU 缓存失效,开销陡增
ConcurrentQueue<t></t>:线程用
SpinWait短暂自旋重试,多数操作在用户态完成,避免了内核态切换 实测数据(100 万次操作):
ConcurrentQueue入队约
45 ms,
Queue+lock约
210 ms;出队同理,快 4–5 倍
什么时候 Queue+lock 反而更优?
别迷信“线程安全=一定更快”。以下情况,手写
lock的
Queue<t></t>更稳、更快: 你需要频繁读取
Count属性(例如做限流、监控或 while 循环批量消费)——
ConcurrentQueue.Count是 O(n) 遍历所有 segment,**在大吞吐下会成瓶颈** 你的“多线程”其实是伪并发:比如只有 1 个生产者 + 1 个消费者,且处理逻辑极轻(几条指令),此时
lock的简单性反而胜过
ConcurrentQueue的原子操作开销 你已在临界区做大量工作(比如解包 + 数据校验 + DB 写入),那锁的占比已很小,换
ConcurrentQueue带来的收益微乎其微
一个真实案例:某 Socket 服务在压测中发现
ConcurrentQueue.Count占 CPU 12%,改用
lock+
Queue<t></t>+ 自增计数器后,吞吐提升 18%。
怎么选?三步判断法
不用猜,按顺序问自己三个问题:
是否真有 ≥2 个线程**同时入队**,或 ≥2 个线程**同时出队**?→ 否:用Queue<t></t>;是:继续 是否需要在循环中高频访问
Count,或依赖精确长度做控制逻辑?→ 是:优先
Queue<t></t>+
lock+ 手动计数;否:继续 单次入/出队操作耗时是否 byte[] 引用,不做解析)?→ 是:
ConcurrentQueue更合适;否(如要 JSON 反序列化):两者差异收敛,可任选,但
ConcurrentQueue代码更干净
Socket 编程里最常见的是「多接收线程入队 + 单工作线程出队」,这种混合模式下,
ConcurrentQueue仍是首选——只要别在
while (!queue.IsEmpty) { ... } 里反复调 Count就行。
