“线程安全的” Dictionary(TKey,TValue)
这是一篇翻译,专门介绍Dictionary线程安全问题,原文网址如下
http://www.grumpydev.com/2010/02/25/thread-safe-dictionarytkeytvalue/
翻译的不对之处,请指正。
介绍
一个宠物项目,我目前正在研究中需要使用内部字典来存储“注册”的数据,这是一个相当普遍的要求。 对于这个特殊的项目,.net 3.5中,我想至少尝试使其“线程安全”的,
着眼于将其移动到ConcurrentDictionary,.NET4中保证线程不仅是安全的,而且具有更精细的锁提高多线程性能。
一个再简单不过的例子,却有许多人犯着这样的错误。
1.只是锁定写入?
很明显,我们需要围绕着写同步原语(syncronisation primitive)类型的操作,但第一印象可能会使你认为读应该没问题-----尤其是如果我们坚持优先TryGetValue模式,而不是“如果它存在,那么得到的值”:
object myValue; // This is obviously not thread safe.
// Something else can alter the collection
// between ContainsKey and reading the
// value.
if (dictionary.ContainsKey("Testing"))
{
myValue = dictionary["Testing"];
}
//Using TryGetValue looks safe though?
//Doesn't it?!
if (!dictionary.TryGetValue("Testing", out myValue)) throw new KeyNotFoundException();
不幸的是,如果使用Reflector查看器,看看TryGetValue是如何实现的,作为上面的第一种方法,很明显它具有完全相同的并发问题:
public bool TryGetValue(TKey key, out TValue value)
{
int index = this.FindEntry(key);
if (index >= )
{
value = this.entries[index].value;
return true;
}
value = default(TValue);
return false;
}
2.因此,我将锁定读取和写入?
下一个显而易见的方法是要找到我们的代码中无处不在的Dictionary,用于读取或写入,并使用同步原语(syncronisation primitive),例如锁 ,以确保我们任何时候只在单个线程访问它:
private readonly object padlock = new object();
private readonly Dictionary<string, object> dictionary = new Dictionary<string, object>(); private void Test()
{
object myValue; // Now we lock before we do anything lock (padlock)
{ if (dictionary.ContainsKey("Testing"))
{
myValue = dictionary["Testing"];
}
}
lock (padlock)
{ if (!dictionary.TryGetValue("Testing", out myValue)) { } }
}
很简单,但你依赖锁定周围的每一个访问,这不仅难看,而且如果你错过了一个,也可能容易出现错误。 因此,一旦把我们代码迁移到.NET 4。在新的ConcurrentDictionary,我们将不得不通过代码并依次取出每个锁 – 这工作相当辛苦!
3.组合(组合设计模式的实现)
在这种方法中,总结了我们在自己的类中使用讨厌地非线程安全的Dictionary,让我使用想用的方法,并采取相应的任何锁。 这个类只实现了“array” 的访问和TryGetValue,但是这个方法足够用了:
public class SafeDictionary<TKey, TValue>
{ private readonly object _Padlock = new object();
private readonly Dictionary<TKey, TValue> _Dictionary = new Dictionary<TKey, TValue>();
public TValue this[TKey key]
{
get
{
lock (_Padlock)
{
return _Dictionary[key];
}
}
set
{
lock (_Padlock)
{
_Dictionary[key] = value;
}
}
}
public bool TryGetValue(TKey key, out TValue value)
{
lock (_Padlock)
{
return _Dictionary.TryGetValue(key, out value);
}
}
}
当我们防止任何直接进入Dictionar和每当我们需要访问它并在内部使用我们的锁的时候,我们现在可以使用代码SafeDictionary无需担心并发问题 - 无论是读和写操作!
4.到 .Net 4 ?
正如我前面提到的,.NET 4将支持数个“线程安全”的集合,其中包括Dictionary,在新的System.Collections.Concurrent命名空间 。 因此我们有自己实现的SafeDictionary,有以下几个特点:
我们可以通过我们的代码并替换所有引用SafeDictionary与ConcurrentDictionary。在我们的主代码中没有任何锁,以至于我们可以这个直接替换。
我们可以改变我们的SafeDictionary内部使用一个ConcurrentDictionary,并删除所有的内部锁。
如果我们不介意使用额外的方法,我们可以删除所有来自SafeDictionary实例和继承ConcurrentDictionary:
public class SafeDictionary<Tkey, TValue> : ConcurrentDictionary<Tkey, TValue>
{ }
5.结论
相当长的博客文章提交一个相当简单的问题,但有时候碰巧碰到简单的并发可以是失误和头痛的根源。 一旦.NET 4中到达其并发集合 , 并行扩展和并行调试选项有望至少*这个头痛的事情会自行消失。
“线程安全的” Dictionary(TKey,TValue)的更多相关文章
- C#字典 Dictionary<Tkey,Tvalue> 之线程安全问题 ConcurrentDictionary<Tkey,Tvalue> 多线程字典
ConcurrentDictionary<Tkey,Tvalue> Model #region 程序集 mscorlib, Version=4.0.0.0, Culture=neutra ...
- .net源码分析 – Dictionary<TKey, TValue>
接上篇:.net源码分析 – List<T> Dictionary<TKey, TValue>源码地址:https://github.com/dotnet/corefx/blo ...
- .NET中Dictionary<TKey, TValue>浅析
.NET中Dictionary<TKey, Tvalue>是非常常用的key-value的数据结构,也就是其实就是传说中的哈希表..NET中还有一个叫做Hashtable的类型,两个类型都 ...
- C# .Net 中字典Dictionary<TKey,TValue>泛型类 学习浅谈
一.综述: Dictionary<TKey,TValue>是在 .NET Framework 2.0 版中是新增的.表示键值对的集合,Dictionary<TKey,TValue&g ...
- Dictionary<Tkey.TValue>与SortedList
一.概述 表示Key/Value集合,可以添加删除元素,允许按Key来访问元素.是Hashtable的泛型等效类. 它需要一个相等实现来确定键是否相等,可以使用实现了IEqualityComparer ...
- c# 扩展方法奇思妙用基础篇五:Dictionary<TKey, TValue> 扩展
Dictionary<TKey, TValue>类是常用的一个基础类,但用起来有时确不是很方便.本文逐一讨论,并使用扩展方法解决. 向字典中添加键和值 添加键和值使用 Add 方法,但很多 ...
- Dictionary<TKey, TValue> 类
C# Dictionary<TKey, TValue> 类 Dictionary<TKey, TValue> 泛型类提供了从一组键到一组值的映射.字典中的每个添加项都由一个值及 ...
- C# 字典 Dictionary<Tkey,Tvalue>
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来.我们都知道计算机技术发展日新月异,速度惊人的快,你我稍不留神,就会被慢慢淘汰!因此:每日不间断的学习是避免被 ...
- 巧用Dictionary<TKey,TValue>,完成客户需求
前几天与客户沟通一个项目,客户对其中某个模块提了一个需求. 把从数据库中取出的对物品的统计重新拆分重新统计.鉴于用文字不能清除的表达需求,我将该需求画出来,便于理解. 需求如下图: 就是A,B,C D ...
随机推荐
- Django——Django中的QuerySet API 与ORM(对象关系映射)
首先名词解释. ORM: 对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型 ...
- 【Java】Java_09 类型转换
1.自动类型转换 自动类型转换:容量小的数据类型可以自动转换为容量大的数据类型.在图中,黑色的实线表示无数据丢失的自动类型转换,而红色的虚线表示在转换时可能会精度的损失. 特例: 可以将整型常量直接赋 ...
- 阿里云OSS服务开通STS安全令牌
搭建直传服务需要完成以下准备工作: 开通OSS,并且创建Bucket. 开通STS服务. 登录 OSS管理控制台. 在OSS概览页中找到基础配置区域,单击 安全令牌,如下图所示: 进入到 安全令牌快捷 ...
- CREATE SEQUENCE添加自增序列及NEXT VALUE FOR返回序列号
From :https://msdn.microsoft.com/zh-cn/library/ff878091.aspx 语法: CREATE SEQUENCE [schema_name . ] se ...
- C语言基础(19)-结构体,联合体,枚举和typedef
一.结构体 1.1 结构体struct定义及初始化 #include <stdio.h> // 这个头文件在系统目录下 #include <stdlib.h> // 使用了sy ...
- DataUml Design 介绍11 - DataUML 1.5版本功能(支持无Oracle客户端连接,有图有真相)
DataUML Design1.5版本主要更新内容包括: 1.优化数据库登录界面: 2.查询分析器智能提示: 3.优化数据库浏览插件,数据库登录组件,支持历史记录缓存: 4.支持无Oracle客户端连 ...
- 在linux下使用curl
使用curl从 ftp下载文件 curl ftp://192.168.31.164/lrzsz-0.12.20.tar.gz --user root:123456 -o lrzsz-0.12.20.t ...
- 我的第九个java程序--spring和mybatis整合(java project)
思路:入口程序读spring的配置文件-配置文件注入给程序bean--程序拿到bean以操作对象的手法查出程序 入口程序HelloWorld.java package HelloWorld; impo ...
- Oracle Parallel模式
一.Parallel 1. 用途 强行启用并行度来执行当前SQL.这个在Oracle 9i之后的版本可以使用,之前的版本现在没有环境进行测试.也就是说,加上这个说明,可以强行启用Oracle的多线程处 ...
- [浪风JQuery开发]jquery最有意思的IFrame类似应用--值得深入研究
前几天一时兴起答应朋友的需求--做一个外国的企业网站: 本想做就做呗,可没想我辛辛苦苦用浪风认真php平台开发后,对方来一句我服务器不能安装其他程序,请给我用frame框架开发. 浪风那是一个苦字难言 ...