集合类的需求总是源源不断,因此,不管是1.0到2.0的泛型,还是3.0到4.0的并行(本文的并行指Concurrent,非 Parallel),.NET每个版本总会伴随着一些集合类的增长。由于并行计算现在已经越来越流行,这里我将对.NET 4.0中新增的命名空间System.Collections.Concurrent和它下面的类做一些简单的介绍。

  为什么需要Concurrent?

  相信不少朋友都有多线程编程的经历吧,不过在.NET 4.0以前,多线程编程下很容易出问题,先看个简单的例子吧。

static void main()
{
  myList = new List<string>();
  for (int i = 0; i < 1000; i++)
  {
    myList.Add(i.ToString());
  }
  new Thread(T2).Start();
  new Thread(T3).Start();
}
static IList<string> myList;
static void T2()
{
  Thread.Sleep(100);
  for (int i = 0; i < 50; i++)
  {
    myList.Remove(i.ToString());
  }
}
static void T3()
{
  foreach (var a in myList)
  {
    Console.WriteLine(a);
  }
}

  在这个例子中,我们首先初始化一个长度为1000数组,然后我们开启两个线程,一个进行删除操作,另外个则进行简单的读操作。运行代码的话你会发现程序会抛出InvalidOperationException,因为系统集合在被读的同时被修改了,因此列举操作可能不能执行。

  当然在4.0以前我们也有办法避免这种类似的操作,比如我们可以对要操作的对象加锁。即我们可以在对myList集合进行读写操作之前对其添加代码lock (myList)。

然而这种方式毕竟不够简洁,并且在更复杂的情况下它可能会显得非常繁琐。这时候支持并行操作的集合应运而生了。

  有哪些Concurrent集合?

  在System.Collections.Concurrent公开的类并不多,他们分别在两个不同的dll中存在,其中在System.dll中仅仅一个BlockingCollection<T>和ConcurrentBag<T>,在mscorlib.dll中则稍多一些,他们分别是ConcurrentQueue<T>, ConcurrentStack<T>, ConcurrentDictionary<TKey, TValue>。不过对于日常开发来说,他们基本够用。下面我们来一个个看下这些类的构造吧。

  首先看看mscorlib中的几个类,这些类其实我们在.NET 2.0中已经接触过它们的普通版本,因此它们功能基本不变,因此你仍然可以像以前那样使用普通版本的哈希表,队列和堆栈来使用它们。

  不过并行类不仅仅简单以前的集合类改造成线程安全的并行类,它同时还提供了一些更丰富的功能,由于Lamda表达式的引入,现在在 ConcurrentDictionary<TKey, TValue>你可以通过AddOrUpdate或GetOrAdd添加自己的值生成方案。这使得我们在生成键值对的时候更加方便和简单了。如:

ConcurrentDictionary<int, string> td = new ConcurrentDictionary<int, string>();
Func<int, string> genVar = (i) => i.ToString();
Task.Factory.StartNew(() =>
{
  for (int i = 0; i < 1000; i++)
  {
    td.GetOrAdd(i, genVar);
  }
});
Task.Factory.StartNew(() =>
{
  Func<int, string, string> updateVar = (key, oldVar) => oldVar + key;
  td.AddOrUpdate(0, genVar, updateVar);
  Console.WriteLine(td[0]);
}).Wait(); 

我们可以看到,现在我们在取值的时候,如果哈希表中没有该值的话我们可以自己生成,或者我们在添加新的值的时候如果碰到重复键值的时候也可以很方便的解决掉了。相对以前在添加或者查找数据时痛苦的判断,这种方式更加简洁和方便。

  其他几个类相对来说函数使用变化不大,唯一区别比较大的也是在Concurrent命名空间中很常见的各种try函数操作。

  接着我们来看看在System.dll中的并行集合,这里面的两个类在以前的.NET中是没有的。首先看看 ConcurrentBag<T>,顾名思义,这个类提供并行数据包的功能,这个类相对来说构造比较简单,它继承自四个接口:IProducerConsumerCollection<T>, IEnumerable<T>, ICollection, IEnumerable,后面三个集合类常用的接口我们当然很熟悉,而且由于实现了IEnumerable<T>接口,ConcurrentBag<T>也支持LINQ操作。不过这里有个特殊的接口 IProducerConsumerCollection<T>我们以前没有见过,虽然是个新的接口,但故名思意,这个接口提供了生产者/消费者的集合操作,它提供了四个基本的方法:CopyTo(T[],int), ToArray(), TryAdd(T), TryTake(out T)。其中我们主要关注后面的两个方法,TryAdd是添加元素操作,而TryTake则是取元素操作。不过在ConcurrentBag 中,TryAdd方法被设置为protected,外部对象需要通过Add操作来添加元素。另外,取元素的话,除了TryTake之外,我们还可以通过 TryPeek来取集合当前的最后一个元素而不删除它。下面来看看例子:

static void main()
{
  ConcurrentBag<string> bag = new ConcurrentBag<string>();
  Task.Factory.StartNew(() =>
  {
    for (int i = 0; i < 1000; i++)
    {
      bag.Add(i.ToString());
    }
    bag.Add("Last");
  });
  Task.Factory.StartNew(() =>
  {
    foreach (string item in bag)
    {
      Console.WriteLine(item);
    }
  }).Wait();
} 

  BlockingCollection<T>相对来说,要稍微复杂一些,它实现了四个接口:IEnumerable<T>, ICollection, IEnumerable, IDisposable,因此该集合同样支持LINQ,不仅如此,它也提供了比ConcurrentBag更加丰富的功能。如 CompleteAdding和超时设置的TryAdd和TryTake方法等等。

  总结

  随着多线程和并行编程的要求越来越多,相信在未来,.NET家族新增的这些类将会在我们的日常编程生活中越来越常见,所以掌握它们也显得越来越又必要了。

.NET 4.0新增命名空间:System.Collections.Concurrent相关推荐

  1. .Net Framework System.Collections 集合类

    本文内容 集合类 性能 最近复习了一下集合,C# 关于集合的类蛮多,但我除了 List 那几个经常用之外,其他的用得还真不多(只在小范围使用),但其实,每个集合类都各有自己适用的场景,功能也很强大.尤 ...

  2. C# 4.0 新增特性

    之前的文章中,我们曾介绍过C#的历史及C# 4.0新增特性,包括:dynamic. 命名和可选参数.动态导入以及协变和逆变等.今天我们结合代码实例来具体看一下C#4.0中的四个比较重要的特性. 1.d ...

  3. error CS0234: 命名空间“System.Drawing”中不存在类型或命名空间名称“Image”

    c#开发时报错: error CS0234: 命名空间"System.Drawing"中不存在类型或命名空间名称"Image" 右键项目,有个引用,添加引用,弹 ...

  4. 类型实现《程序员的第一年》--------------C#中System.Collections.Generic.SortedDictionary 的使用...

    在改章节中,我们主要介绍类型实现的内容,自我感觉有个不错的建议和大家分享下 SortedDictionary<TKey,TValue> 类型参数 TKey 字典中的键的类型. TValue ...

  5. 使用ILSpy探索C#7.0新增功能点

    第一部分: C#是一种通用的,类型安全的,面向对象的编程语言.有如下特点: (1)面向对象:c# 是面向对象的范例的一个丰富实现, 它包括封装.继承和多态性.C#面向对象的行为包括: 统一的类型系统 ...

  6. 必须进行支持的游戏方可使用此功能_C#8.0 新增功能

    (给DotNet加星标,提升.Net技能) 转自:张传宁cnblogs.com/SavionZhang/p/11201818.html C#8.0提供了许多增强功能 1.Readonly 成员 可将 ...

  7. System.Collections深入探讨--如何创建自定义的集合类

    关键字:collection集合,ArrayList数组队列,Generic 泛型,List<T>列表,自定义集合类 正文:     在System.Collections namespa ...

  8. [corefx注释说]-System.Collections.Generic.StackT

    对C#里边的基础类库有充分的好奇心,所以就心血来潮写一下,这个就不定期更新了,想什么时候写就什么时候写好了.这里弱弱的吐槽一下CSDN的博客.为了以防万一,会在我其他的博客做一下备份. 废话不多说 切 ...

  9. C#命名空间 System.IO思维导图

    C#命名空间 System.IO思维导图 #mermaid-svg-43CMmjO0R5l1qNrR {font-family:"trebuchet ms",verdana,ari ...

最新文章

  1. 老生常谈 String、StringBuilder、StringBuffer
  2. 第三周项目四-穷举法解决组合问题
  3. python3.6.5安装教程-Centos7 安装Python3.6.5
  4. python爬虫案例-Python3爬虫三大案例实战分享
  5. 【MFC】在CHtmlView中准确判断页面加载完成
  6. caffe 加入 cudnn编译
  7. mysql 中 and和or 一起使用和之间的优先级
  8. mimes.php,php – Laravel文件上传验证
  9. 关于使用weex开发app上线App Store问题
  10. Zookeeeper开源客户端curator watcherAPI的使用
  11. 软件测试常见分辨率测试,如何用imatest测分辨率 imatest软件测试分辨率图文教程...
  12. 多目标最优化模型及算法应用(NSGA-II)
  13. 网站没有外链 如何计算权重
  14. 频率与时间,电容,电感,电阻,计算机,分贝 单位换算
  15. 笔记本 WIFI 热点批处理文件
  16. 仿b站的动漫视频网站
  17. Citus 分布式 PostgreSQL 集群 - SQL Reference(创建和修改分布式表 DDL)
  18. 电脑开机自动联服务器,如何让Mac开机自动连接到NAS或网上邻居上的电脑
  19. 最大公约数 / 最小公倍数
  20. PinnedSectionListView原理完全透析

热门文章

  1. 信息学奥赛一本通 2051:【例3.1】偶数
  2. 信息学奥赛一本通(1246:膨胀的木棍)
  3. 一半的一半(51Nod-2382)
  4. Telephone Linse(POJ-3662)
  5. 回文质数(洛谷-P1217)
  6. 15 SD配置-企业结构-分配-给工厂分配起运点
  7. 字符串16进制数字转换到Ascll字符串
  8. C++:类的成员函数
  9. 企业微信添加机器人播报天气
  10. Arm 64位 汇编入栈和出栈