并发集合
1 为什么使用并发集合?
原因主要有以下几点:
注意:
与经典集合相比,并发集合会有更大的开销,因此在串行代码中使用并发集合无意义,只会增加额外的开销且运行速度比访问经典集合慢。
2 并发集合
1)ConcurrentQueue:线程安全的先进先出 (FIFO) 集合
主要方法:
说明:
2)ConcurrentStack:线程安全的后进先出 (LIFO) 集合
主要方法及属性:
说明:
3) ConcurrentBag:元素可重复的无序集合
主要方法及属性:
说明:
4)BlockingCollection:实现
System.Collections.Concurrent.IProducerConsumerCollection<T> 的线程安全集合,提供阻塞和限制功能
主要方法及属性:
说明:
限界功能可控制内存中集合最大大小,这对于需要处理大量元素的时候非常有用。
5)ConcurrentDictionary:可由多个线程同时访问的键值对的线程安全集合。
主要方法
说明:
6)IProducerConsumerCollection:定义供生产者/消费者用来操作线程安全集合的方法。 此接口提供一个统一的表示(为生产者/消费者集合),从而更高级别抽象如 System.Collections.Concurrent.BlockingCollection<T>可以使用集合作为基础的存储机制。
3.常用模式
1)并行的生产者-消费者模式
定义:
生成者和消费者是此模式中的两类对象模型,消费者依赖于生产者的结果,生产者生成结果的同时,消费者使用结果。
图1 并行的生产者-消费者模式
说明:
2)流水线模式
定义:
流水线由多个阶段构成,每个阶段由一系列的生产者和消费者构成。一般来讲前一个阶段是后一个阶段的生成者;依靠相邻两个阶段之间的缓冲区队列,每个阶段可以并发执行。
图2 并行的流水线模式
说明:
4 使用方式
仅以ConcurrentBag和BlockingCollection为例,其他的并发集合与之相似。
ConcurrentBag
1 List<string> list = ......
2 ConcurrentBag<string> bags = new ConcurrentBag<string>();
3 Parallel.ForEach(list, (item) =>
4 {
5 //对list中的每个元素进行处理然后,加入bags中
6 bags.Add(itemAfter);
7 });
BlockingCollection—生产者消费者模式
1 public static void Execute()
2 {
3 //调用Invoke,使得生产者任务和消费者任务并行执行
4 //Producer方法和Customer方法在Invoke中的参数顺序任意,不论何种顺序都会获得正确的结果
5 Parallel.Invoke(()=>Customer(),()=>Producer());
6 Console.WriteLine(string.Join(",",customerColl));
7 }
8
9 //生产者集合
10 private static BlockingCollection<int> producerColl = new BlockingCollection<int>();
11 //消费者集合
12 private static BlockingCollection<string> customerColl = new BlockingCollection<string>();
13
14 public static void Producer()
15 {
16 //循环将数据加入生成者集合
17 for (int i = 0; i < 100; i++)
18 {
19 producerColl.Add(i);
20 }
21
22 //设置信号,表明不在向生产者集合中加入新数据
23 //可以设置更加复杂的通知形式,比如数据量达到一定值且其中的数据满足某一条件时就设置完成添加
24 producerColl.CompleteAdding();
25 }
26
27 public static void Customer()
28 {
29 //调用IsCompleted方法,判断生产者集合是否在添加数据,是否还有未"消费"的数据
30 //注意不要使用IsAddingCompleted,IsAddingCompleted只表明集合标记为已完成添加,而不能说明其为空
31 //而IsCompleted为ture时,那么IsAddingCompleted为ture且集合为空
32 while (!producerColl.IsCompleted)
33 {
34 //调用Take或TryTake "消费"数据,消费一个,移除一个
35 //TryAdd的好处是提供超时机制
36 customerColl.Add(string.Format("消费:{0}", producerColl.Take()));
37 }
38 }
-----------------------------------------------------------------------------------------
时间仓促,水平有限,如有不当之处,欢迎指正。