注:本文附带的源代码包含了几个班的Matrix平台。该平台是完全免费的,开源软件。为了获得其源代码和二进制,去网站,请参阅下载部分。简介
,随着多核心处理器的增长,多线程访问数据的问题变得非常重要。本文介绍了一个简单的应用程序同时访问一个通用的。NET数据收集的问题的具体解决方案。尽管正在设计之前释放NET 4.0中的多线程能力的集合,热插拔集合还提供了一个可行的替代System.Collections.Concurrent命名空间提供。使用任何工具,它是最重要的,使用它在适当情况下,所以在这篇文章中,以帮助您与您所选择的使用方案,优点和缺点概述。与在同一时间从多个线程访问一个普通收藏的问题是什么?
从System.Collections命名空间中的默认的泛型集合不是线程安全的,如果在同一时间从多个线程试图访问一个集合实例,这往往会导致"收集修改??异常(系统InvalidOperationException异常)。
下面是一个很简单的例子,问题出现了:void MethodOne(int x)
{
_collection.Add(x);
}
void MethodTwo()
{
foreach(int val in _collection)
{
// Do something with val.
}
}
,如果MethodOne()和MethodTwo()是在同一时间执行两个不同的线程(或更多),这必将导致发生异常。什么热插拔呢?
热交换是一种编程技术,允许建立能够与尽可能多的线程工作,同时根据需要的馆藏没有例外的危险。这些集合设计看起来像正常的泛型集合的很多文章所附的源代码提供的实现提供了列表IList和IDictionary的集合字典,但是同样的机制也可以应用于其他类型的集合。热插拔集合有一个很大的优势呢??锁,少读访问。这将确保绝对最高性能成为可能并发读访问时做的。如何运作?
背后的热交换的原理很简单。它是基于事实,同时操作如修改或清除现有的集合耗时的,需要明确的线程访问控制,但操作的"交换??在单步执行。在我们的例子中,"交换??是指改变一个类的实例变量的值从一个实例到另一个。如果我们纪念??代码>挥发??关键字字段,这指示编译器可执行代码,这样"... ...系统总是读取请求一个volatile对象的当前值?? (根据MSDN的)。之间的旧的和新的价值变化的实际操作中始终是线程安全的,因为。NET环境,保证托管指针总是指向一个实际值,如果已分配。
热交换的核心运作原则如下:
当集合的修改要求,热插拔收集准备的内部收集和交换这与现有的实例的新副本全新副本。
所有只读操作都指向目前使用的实例。
这两个简单的步骤就足够,以确保集合是线程安全的,因为所有的访问是对现有的集合静态版本进行的。作为一个这样做的结果 - 一旦一个线程开始遍历集合,它是保证,它将在同一版本的收集工作,它开始时。如果本次迭代过程中发生的变化,这些变化将所有后续迭代尝试访问。
只锁定正在修改集合时发生。这是必需的,以确保所有的改变都反映在最终版本的集合。
在本文中提供的的实现,有也被添加了一些额外的方法,即允许考虑到的事实,收集可能的变化,当一个线程是访问。这些都是TryAdd()和TryGet()方法,往往可以发现类似的方法,在多线程能够集合,与他们一起工作的性质,因为相比传统的集合,是一个有点不同。
实施
热插拔技术的实施是非常简单的。下面是一个局部视图的HotSwapList实现,你可以看到在文章的代码的其余部分。我选择了一个方法,实施两个方面 - 热交换列表操作在两个方向之一是提供内部数据,基于目前的内部参考,和其他修改内部参考??。
这是一个从热交换清单实施的提取,呈现出一些实施的关键功能:{C}热插拔集合VS。NET System.Collections.Concurrent集合
微软NET 4.0中引入的并发线程访问的工作,即设计的集合:BlockingCollection,ConcurrentBag,ConcurrentDictionary,ConcurrentQueue和ConcurrentStack。热插拔集合。NET并发集合的方式同样的问题,并在相当不同的结果,这个结果,当谈到用途及特点有一个很大的区别。 HowSwap集合的优势和缺点,下面是一个列表相比,NET 4.0中的。热插拔的优点最大读取速度
由于其设计,热插拔集合提供了最好的理论上是可行的读取速度。这通常是一个非常小的优势,只有百分之几,但它可以真正做到在非常高的性能应用不同。它也可以证明是有益的的,如果使用大量的线程同时访问(前为6-8或更多),较为常见的场景,将成为在不久的将来引进大量多核CPU。替代操作系统的全面支持
单声道。NET 2.0框架的全力支持,并全力支持NET 4.0仍是给予截止日期(写这篇文章时),所以在情况下,你打算使用并发收集什么比微软的Windows不同,这篇文章是一个出色的解决方案。遍历集合的固定版本
一旦产生一个迭代器,它经过收集,目前存在的迭代器创建。
简单
您只使用您需要什么,你有它的所有源代码,这从长远来看,提高管理和降低风险。热插拔的缺点极低的写/修改速度,特别是大的项目设置
再次由于其设计,修改热插拔集合是一个非常缓慢的过程,因为正在取得一个完整的重复。例如,这可以部分解决,使用的方法,可以让一次添加多个项目??AddRange(中HotSwapList)。有条件的使用
有少数情况下使用列表热插拔收集可以带来错误的结果;这些情况下很容易预见,并详细介绍了"做和不该做什么本文的部分??。应用
热插拔技术是广泛使用的Matrix平台({A2})的组成部分,并已被证明是一个出色的整体解决方案。意识到自己的优势和劣势是非常重要的的,因为他们从一般通用的可用性略有不同。NET集合,并提供了一个"专门??的解决方案。
为热插拔使用的一般规则是看为小到中等量的修改集合或集合的情况下,有体积小。技术的使用其他的可能性
热插拔技术还可以在其他情况下使用,例如,在访问类成员实例,没有明确的锁定。下面是一个例子:void MyMethod()
{
// Grabbing the instance and storing it in separate local variable prior to using it,
// guarantees we shall always use a valid instance,
// and there is no danger if other threads change the _instance member
// while we are operating.
CustomClass instance = this._instance;
If (instance != null)
{
instance.PerformAction();
}
}
有一个锁定部分的最低数量(使用锁()关键字,监视器类或其他同步项目),保证您的应用程序的最佳性能,最重要的是大大降低了发生死锁的机会。它还简化了代码,并免除程序员经常检查为尽可能多的胎面问题。
使用这种技术,与其他几个人一起,使我们能够建立一个完整的多线程访问策略,极大地简化了多进程线程应用程序的开发,然而,这偏离大大从目前的主题,并应在另一个单独的一篇文章的主题。例子??该做什么和不该做什么HotSwapDictionary
由于其执行的性质,热插拔字典实施的所有操作都在所有可能的情况下,线程安全的。HotSwapList
热插拔列表需要慎用2,特殊情况下使用,它可能会导致错误,如果使用不当发生。
假设我们有以下成员:
案例1:克隆热插拔列表集合正确的HotSwapList<int> _list = new HotSwapList<int>();
List<int> clone = new List<int>(_list.AsReadOnly());
不正确
列表构造函数作为参数的IEnumerable,所以迭代应该是线程安全的,即使我们只传递_list。然而,内部列表构造测试IList接口的类,如果发现使用它。这可能会导致不正确而被修改,迭代集合,并导致异常。案例2:迭代正确的,因为一旦产生一个枚举,它会始终指向集合的初始版本List<int> clone = new List<int>(_list);
正确的,因为创建一个只读包装固定的集合中的当前实例foreach(int item in _list)
{// Use item.
int p = item;
}
IN正确ReadOnlyCollection<int> clone2 = _list.AsReadOnly();
for (int i = 0; i < clone2.Count; i++)
{
int p = clone2[i];
}
为什么呢?for (int i = 0; i < _list.Count; i++)
{
int p = _list[i];
}
在最后的情况下,收集可能会改变在运行??代码>为??循环。如果发生这种情况,有没有保证的_List [I]实际上会指向现有成员,这可能会导致异常。这是有没有索引的原因之一。NET 4.0 System.Collections.Concurrent命名空间的能力集合。案例3:暴露在外部访问的始终是安全的正确的
为什么呢?IEnumerable<int> List
{
get
{
return _list;
}
}
热插拔收集所有的IEnumerable成员在任何情况下使用是安全的,因为他们依靠统计员使用,而这些点上,以相同的子实例一旦创建。使用
要使用连接到这篇文章的集合的源代码,只需将它们添加到项目,并在您的multh线程环境中使用的类;唯一要牢记的情况下的用法HotSwapList需要做适当的回避可能的例外。