.NET中的并行集合
作为.NET 4并行扩展的一部分,新的System.Collections.Concurrent命名空间中包含一些新的集合。它们被设计为在含有较少锁的多线程并发操作时是安全的。该命名空间下还包含三个用于对并发操作的集合进行分区的类,但在此我们不讨论它们。
1. IProducerConsumerCollection和BlockingCollection
IProducerConsumerCollection
被设计用于BlockingCollection
,有三个新的集合实现了该接口。在描述队列和栈时,我说过它们通常用于为稍后的处理存储工作项;生产者/消费者模式是一种并行执行这些工作项的方式。有时只有一个生产者线程创建工作,多个消费者线程执行工作项。在其他情况下,消费者也可以是生产者,例如,网络爬虫(crawler)处理一个Web页面时会发现更多的链接,供后续爬取。
IProducerConsumerCollection
是生产者/消费者模式中数据存储的抽象,BlockingCollection
以易用的方式包装该抽象,并提供了限制一次缓冲多少项的功能。
BlockingCollection
假设没有东西会直接添加到包装的集合中,所有相关方都应该使用包装器来对工作项进行添加和移除。构造函数包含一个重载,不传入IProducerConsumerCollection
参数,而使用ConcurrentQueue
作为后台存储。
IProducerConsumerCollection
只提供了三个特别有趣的方法:ToArray
、TryAdd
和TryTake
。
ToArray
将当前集合内容复制到新的数组中,这个数组是集合在调用该方法时的快照。- TryAdd和TryTake都遵循了标准的TryXXX模式,试图向集合添加或移除项,返回指明成功或失败的布尔值。它允许有效的失败模式,降低了对锁的需求。例如在
Queue
中,要把“验证队列中是否有项”和“如果有项就进行出队操作”这两个操作合并为一个,就需要一个锁——否则Dequeue
就可能抛出异常(例如,当队列有且仅有一个项时,两个线程同时判断它是否有项,并且都返回true
,这时其中一个线程先执行了出队操作,而另一个线程再执行出队操作时,由于队列已经空了,因此将抛出异常。——译者注)。
BlockingCollection
包含一系列重载,允许指定超时和取消标记,可以在这些非阻塞方法之上提供阻塞行为。通常不需要直接使用BlockingCollection
或IProducerConsumerCollection
,你可以调用并行扩展中使用了这两个类的其他部分。但了解它们还是很有必要的,特别是在需要自定义行为的时候。
2. ConcurrentBag、ConcurrentQueue和ConcurrentStack
- 框架自带了三个
IProducerConsumerCollection
的实现。本质上,它们在获取项的顺序上有所不同;队列和栈与它们非并发等价类的行为一致,而ConcurrentBag
没有顺序保证。 - 它们都以线程安全的方式实现了
IEnumerable
。GetEnumerator()
返回的迭代器将对集合的快照进行迭代;迭代时可以修改集合,并且改变不会出现在迭代器中。这三个类都提供了与TryTake类似的TryPeek
方法,不过不会从集合中移除值。与TryTake
不同的是,IProducerConsumerCollection
中没有指定TryPeek方法。
3. ConcurrentDictionary<TKey, TValue>
ConcurrentDictionary<TKey, TValue>
实现了标准的IDictionary<TKey, TValue>
接口(但是所有的并发集合没有一个实现了IList
),本质上是一个线程安全的基于散列的字典。它支持并发的多线程读写和线程安全的迭代,不过与上节的三个集合不同,在迭代时对字典的修改,可能会也可能不会反映到迭代器上。- 它不仅仅意味着线程安全的访问。普通的字典实现基本上可以通过索引器提供添加或更新,通过Add方法添加或抛出异常,但ConcurrentDictionary<TKey, TValue>提供了名副其实的大杂烩。你可以根据前一个值来更新与键关联的值;通过键获取值,如果该键事先不存在就添加;只有在值是你所期望的时候才有条件地更新;以及许多其他的可能性,所有这些行为都是原子的。在开始时都显得很难,但并行团队的Stephen Toub撰写了一篇博客,详细介绍了什么时候应该使用哪一个方法(参见http://mng.bz/WMdW)。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!