10

.NET 4.0 引入了System.Collections.Concurrent命名空间:

System.Collections.Concurrent命名空间提供了几个线程安全的集合类,当多个线程同时访问集合时,应使用这些类代替System.CollectionsSystem.Collections.Generic命名空间中的相应类型”

该类SynchronizedCollection<T>(自 .NET 3.0 起可用):

“提供一个线程安全的集合,其中包含由泛型参数指定的类型的对象作为元素”

...在System.Collections.Generic命名空间中。

那么,为什么SynchronizedCollection<T>类是线程安全的但不是并发的呢?

是什么使SynchronizedCollection<T>泛型类与 中的集合不同且不兼容System.Collections.Concurrent

更新: 让我重新表述这个问题:属于命名空间的所有泛型集合中的共同点和区别新特性是什么,这在泛型类System.Collections.Concurrent中不存在(并且在使用时是不可能的)?SynchronizedCollection<T>

我将标题更改为“System.Collections.Concurrent向 .NET 3.0 添加了哪些 .NET 4.0 集合的功能SynchronizedCollection?”。 但大多数情况下,我很想知道是什么使得在 .NET 3.0 的基础上无法做到这一点

更新2:关于注释:

“这个问题在这里可能已经有了答案:

SynchronizedCollection 和其他并发集合有什么区别?"

就我的问题而言,答案令人困惑——新功能是进化的(使用 .NET 4.0 之前的功能)还是革命性的(在 .NET 4.0 之前的版本中不可用)?

4

3 回答 3

9

以前的线程安全集合类有一个相当大的缺陷,它们不能以线程安全的方式迭代。迭代通常很难使线程安全,没有干净的方法可以使使用迭代器的代码在代码迭代集合知道添加到集合中或从集合中删除的项目。唯一真正安全的方法是在迭代发生时锁定对集合的访问。这是非常不可取的,这样的锁通常会被持有很长时间。下一个最好的方法是制作集合的副本,一个不会被修改的副本,因此可以始终安全地迭代。没有人喜欢该解决方案的 O(n) 存储要求。

.NET 1.0 集合类中的 Synchronized() 方法特别麻烦。微软并没有将迭代不是线程安全的作为秘密。他们甚至添加了代码来检测事故,当线程修改集合时会引发异常。然而,这种异常发生的频率并不高,而且困惑的 .NET 程序员没有阅读警告标签,只是断然假设,无论您做什么,线程安全的集合都是安全的。好吧,当对集合的最基本操作不是线程安全的时候,调用集合“线程安全”当然是个问题。微软的意思是“它是线程安全的,因为使用线程不会破坏集合”。程序员读什么是“它是线程安全的”。Microsoft 没有在 .NET 2.0 通用集合类中重复同样的错误。

这已在 .NET 4 中解决,迭代新集合不会引发异常。他们不会做任何事情来防止您的代码行为不端,因为它正在读取陈旧的数据。这是一个无法解决的问题,你必须自己解决。

于 2013-02-27T12:14:18.203 回答
6

.NET 4.0 的主要焦点是并发性。Microsoft 在 .NET 4.0 中引入了System.Threading.Tasks命名空间,因此添加 System.Collections.Concurrent 命名空间也是有意义的。如其他地方所述,System.Collections.Concurrent 中的集合具有高性能,因为它们以无锁方式实现。这不是一件容易的事,我认为这就是为什么微软认为它属于一个新的主要 .NET 版本而不是 .NET 3.x 的更新。AFAIK 无锁行为是使用通用版本的Interlocked.CompareExchange实现的,这也是 .NET 4.0 的新功能。

如果您对如何实现 System.Collections.Concurrent 的类感兴趣,我建议您阅读 Joe Duffy在 .NET 4.0 发布之前撰写的《Windows 上的并发编程》一书。这本书展示了一些并发集合是如何实现的。

于 2013-02-27T11:07:56.877 回答
1

链接的副本回答了您问题的“新功能”部分。我将在这里谈谈这个笔记:

是什么使得在 .NET 3.0 的基础上无法做到

我的猜测是没有什么不可能的。我怀疑,如果您对 .NET 4.0 中的新类进行反编译,并且(根据需要进行语法更改)自己针对 .NET 3.5 创建此类类,它们会很好地工作。

这与Enumerable.Zip在 .NET 3.5 中手动实现的方式相同,如果 .NET 4.0 不可用。事实上,我记得在某处看到过针对 .NET 2.0的类似 LINQ 的库的实现(当然没有 C# 语言功能!)。

一般来说,对于 .NET,除非库依赖于新的CLR功能,否则没有什么可以阻止针对早期版本重新实现库。这种情况的一个值得注意的例子是泛型:在 .NET 2.0 之前,如果不手动处理每个不同的类,可能使用CodeSmith之类的代码生成工具,就无法获得类型安全的集合支持。

因此,如果没有什么阻止Concurrent.NET 3.5 中类的存在,那么微软为什么不创建它们呢?简单来说就是时间和预算——发货是一个功能,有些功能没有那么重要,所以他们必须等到更高版本。

于 2013-02-27T10:06:55.847 回答