Parallel World 5 – Concurrent Collections (1)

从本节开始,我们将要重点介绍如何解决并行运算中的哪两个问题。竞态问题其实就是一个共享数据的问题,所以许多资料也干脆把这个问题称为Share Data. 在多线程环境中我们知道很多解决这个问题的方法; .NET Framework 4 提供了System.Collections.Concurrent一个新的命名空间来解决这个问题。

当开发人员在开发并行程序的过程中,需要在多个并行Task之间共享一个集合时,这个命名空间提供的Concurrent Collections是最佳选择;它们是线程安全的同时还提供了一个轻量级的同步机制。

这个命名空间提供了以下个基本的并发集合 – ConcurrentBag, ConcurrentDictionary, ConcurrentQueue 、ConcurrentStack和BlockingCollection,OrderablePartitioner<TSource>、Partitioner、Partitioner<TSource>; 还有一个IProducerConsumerCollection<T>接口。前4个在这章中跟大家分享一下,后面几个将在后续文章中跟大家分享。

I. ConcurrentQueue

   1: private const int NUM_MAX = 100;
   2:  
   3: static void Main(string[] args)
   4: {
   5:     ConcurrentQueue<Int32> concurrentQueue = new ConcurrentQueue<Int32>();
   6:    
   7:     try
   8:     {
   9:         Task.Factory.StartNew(() =>
  10:         {
  11:             for (int i = 0; i < NUM_MAX; i++)
  12:             {
  13:                 Console.WriteLine("###################: {0}", i);
  14:                 concurrentQueue.Enqueue(i);
  15:             }
  16:         });
  17:  
  18:         Task.Factory.StartNew(() => {
  19:             for (int i = 0; i < NUM_MAX; i++)
  20:             {
  21:                 int queueElement;
  22:                 bool success = concurrentQueue.TryDequeue(out queueElement);
  23:                 if (success)
  24:                 {
  25:                     Console.WriteLine("-----------------: {0}", queueElement);
  26:                 }
  27:             }
  28:         });
  29:     }
  30:     catch (System.AggregateException ex)
  31:     {
  32:         throw ex;
  33:     }
  34:  
  35:     Console.ReadLine();
  36: }

Queue是遵循FIFO的集合,它提供了三个重要的方法

TryPeek() 获得Queue中的第一个元素,但是并不把它从Queue中移除
TryDequeue() 获得Queue中的第一个元素,并把它从Queue中移除
Enqueue() 把一个元素放到Queue中

执行上面的代码可以得到类似如下的结果:

re

II. ConcurrentStack

Stack是遵循LIFO的集合,它提供了如下一些重要的方法:

Push(T) 在栈顶插入一个元素
PushRange(T[]) 在栈顶插入多个元素
PushRange(T[], int startIndex, int count) 在栈顶插入多个元素,startIndex是指T[]从零开始的偏移量,从此处开始将元素插入到栈的顶部, count是指插入的数量
TryPeek(out T result) 从栈顶返回一个元素,但是并不把它从栈顶移出
TryPop(out T result) 从栈顶返回一个元素,并不把它从栈顶移除
TryPopRange(out T[]) 将从栈顶部弹出的对象添加到的T[]
TryPopRange(out T[]) 将从栈顶部弹出的对象添加到的T[],startIndex是指T[]从零开始的偏移量,从此处开始将元素插入到T[], count是指插入的数量

III. ConcurrentBag

ConcurrentBag无序集合

TryPeek(out T result) 返回一个对象但不移除该对象,
TryTake( out T result)

返回一个对象并移除该对象

IV. ConcurrentDictionary

键/值对集合

AddOrUpdate(TKey, Func<TKey, TValue>, Func<TKey, TValue, TValue>) 如果指定的键尚不存在,则将键/值对添加到 ConcurrentDictionary<TKey, TValue> 中;如果指定的键已存在,则更新 ConcurrentDictionary<TKey, TValue> 中的键/值对。
AddOrUpdate(TKey, TValue, Func<TKey, TValue, TValue>) 如果指定的键尚不存在,则将键/值对添加到 ConcurrentDictionary<TKey, TValue> 中;如果指定的键已存在,则更新 ConcurrentDictionary<TKey, TValue> 中的键/值对。
GetOrAdd(TKey, Func<TKey, TValue>) 如果指定的键尚不存在,则将键/值对添加到 ConcurrentDictionary<TKey, TValue> 中。
GetOrAdd(TKey, TValue) 如果指定的键尚不存在,则将键/值对添加到 ConcurrentDictionary<TKey, TValue> 中。
TryAdd(TKey, TValue) 尝试将指定的键和值添加到 ConcurrentDictionary<TKey, TValue> 中。
TryRemove(TKey, out TValue) 尝试将制定的键和值移除,值将会被放到TResult中。如果移除成功,则返回true.

这个集合中还有一些很有意思的方法,大家可以查看msdn来获得更多的帮助。

原文地址:https://www.cnblogs.com/wildboar/p/2080791.html