ConcurrentQueue (T) 与 Queue(T)
ConcurrentStack 与堆栈
.NET Framework 4 引入了五种专为支持多线程添加和删除操作而设计的集合类型。 为了实现线程安全,这些类
型使用多种高效的锁定和免锁定同步机制。 同步会增加操作的开销。 开销数取决于所用的同步类型、执行的操
作类型和其他因素,例如尝试并行访问该集合的线程数。
在某些方案中,同步开销可忽略不计,使多线程类型的执行速度和缩放水平远远超过其受外部锁保护的非线程安
全同等类型。 在其他方案中,开销可能会导致线程安全类型的执行速度和缩放水平与该类型外部锁定的非线程
安全版本相同,甚至更差。
以下部分提供有关何时使用线程安全集合与其非线程安全同等集合(其读写操作受用户提供的锁定保护)的通用
指南。 由于性能可能因多种因素而异,所以本指南并不针对某特定情况且不一定对所有情况都有效。 如果性能
非常重要,那么确定要使用的集合类型的最佳方式是基于典型计算机配置和负载衡量性能。 本文档使用以下术
语:
纯生成方-使用方方案
任何给定线程要么添加元素,要么删除元素,两种操作不能同时执行。
混合生成方-使用方方案
任何给定线程可同时添加和删除元素。
加速
相对于同一方案中其他类型更快速的算法性能。
可伸缩性
与计算机内核数相称的性能提升。 一种可伸缩的算法,相比两个内核,八个内核上的执行速度更快。
在纯制造者-使用者方案中,每个元素的处理时间都非常短(几条指令),而相比带有外部锁的
System.Collections.Generic.Queue<T>,System.Collections.Concurrent.ConcurrentQueue<T> 可提供适度的性
能优势。 在此方案中,当某一专用线程排队,而另一专用线程取消排队时,ConcurrentQueue<T> 的性能最佳。
如果不强制执行此规则,那么 Queue<T> 在多内核计算机上的执行速度甚至可能稍快于
ConcurrentQueue<T>。
处理时间大约为 500 FLOPS(浮点运算)或更长时,该双线程规则不适用于 ConcurrentQueue<T>,这将具有很好
的可伸缩性。 Queue<T> 在此情况下无法正常伸缩。
在混合制造者-使用者方案中,处理时间非常短时,带外部锁的 Queue<T> 的伸缩性优于
ConcurrentQueue<T>。 但是,处理时间大约为 500 FLOPS 或更长时,ConcurrentQueue<T> 的伸缩性更佳。
在纯制造者-使用者方案中,当处理时间非常短时,System.Collections.Concurrent.ConcurrentStack<T> 和带外部
锁的 System.Collections.Generic.Stack<T> 在使用一个专用推送线程和一个专用弹出线程时的执行性能可能大致
相同。 但是,随着线程数的增加,这两种类型的执行性能会因争用增加而降低,并且 Stack<T> 的执行性能可能
优于 ConcurrentStack<T>。 处理时间大约为 500 FLOPS 或更长时,这两种类型的伸缩速率大致相同。
在混合制造者-使用者方案中,对于小型和大型工作负荷,ConcurrentStack<T> 的速度更快。
使用 PushRange 和 TryPopRange 可能会大大加快访问速度。