惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
Blog — PlanetScale
Blog — PlanetScale
S
Security @ Cisco Blogs
G
GRAHAM CLULEY
L
LINUX DO - 热门话题
AWS News Blog
AWS News Blog
P
Privacy International News Feed
Cyberwarzone
Cyberwarzone
P
Proofpoint News Feed
腾讯CDC
美团技术团队
宝玉的分享
宝玉的分享
博客园 - 聂微东
小众软件
小众软件
T
Threat Research - Cisco Blogs
L
Lohrmann on Cybersecurity
雷峰网
雷峰网
T
Threatpost
The Hacker News
The Hacker News
P
Palo Alto Networks Blog
L
LangChain Blog
Cisco Talos Blog
Cisco Talos Blog
G
Google Developers Blog
V
Vulnerabilities – Threatpost
NISL@THU
NISL@THU
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Engineering at Meta
Engineering at Meta
T
Troy Hunt's Blog
F
Full Disclosure
博客园_首页
The Last Watchdog
The Last Watchdog
S
Secure Thoughts
H
Heimdal Security Blog
Hacker News: Ask HN
Hacker News: Ask HN
C
Check Point Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
PCI Perspectives
PCI Perspectives
Microsoft Security Blog
Microsoft Security Blog
S
Security Affairs
量子位
Cloudbric
Cloudbric
H
Hacker News: Front Page
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
L
LINUX DO - 最新话题
IT之家
IT之家
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Spread Privacy
Spread Privacy
Forbes - Security
Forbes - Security
Security Archives - TechRepublic
Security Archives - TechRepublic

博客园 - jujusharp

异步控制器, 从ASP.NET MVC 2到4 你知道为啥++[[]][+[]]+[+[]] = 10? 我为啥喜欢WinPhone - jujusharp - 博客园 WinPhone开发阶段总结 C#与闭包 .NET程序员学PHP:常见编程错误 .NET程序员学PHP:static关键字 PHP:使用'./include.php'替换'include.php’ C# Tips-2 jQuery 1.4: 15个你应该知道的新特性(译) .NET 4.0新特性-- Corrupted State Exceptions C# 4.0新特性-索引属性 .NET Framework 版本安装调查 C# 4.0 新特性-dynamic 从键盘布局开始说C#中的符号 C# 特性复习-泛型 10个你需要了解的不常见的Html标签(译) C# Small Tips javascript Array.sort() 跨浏览器下需要考虑的问题
.NET 4.0新增命名空间:System.Collections.Concurrent
jujusharp · 2010-03-09 · via 博客园 - jujusharp

集合类的需求总是源源不断,因此,不管是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家族新增的这些类将会在我们的日常编程生活中越来越常见,所以掌握它们也显得越来越又必要了。