改进ConcurrentDictionary并行使用的性能
上一篇文章“ConcurrentDictionary 对决 Dictionary+Locking”中,我们知道了 .NET 4.0 中提供了线程安全的 ConcurrentDictionary<TKey, TValue> 类型,并在某些特定的使用条件下会产生问题。
在 ConcurrentDictionary<TKey, TValue> 类中有一个方法 GetOrAdd ,用于尝试获取一个键值,如果键值不存在则添加一个。其方法签名如下:
public TValue GetOrAdd(
TKey key,
Func<TKey, TValue> valueFactory
) Parameters
key
Type: TKey
The key of the element to add. valueFactory
Type: System.Func<TKey, TValue>
The function used to generate a value for the key
通常,我们会通过如下这种方式来使用:
ConcurrentDictionary<string, ExpensiveClass> dict1
= new ConcurrentDictionary<string, ExpensiveClass>(); string key1 = "";
ExpensiveClass value1 = dict1.GetOrAdd(
key1,
(k) => new ExpensiveClass(k));
这种使用方式会产生一个问题,就是如果特定的类的构造过程比较昂贵(资源消耗、时间消耗等),在并行运行条件下,当第一个线程尝试获取该键值时,发现不存在后开始构建该对象,而在构建的同时,另外一个线程也尝试获取该键值,发现不存在后也开始构建该对象,当第一个线程构造完毕后将对象添加至字典中,而第二个对象也构造完毕后会再次检测字典中是否存在该键值,因为键值已经存在,所以将刚创建完毕的对象直接丢弃,而使用已存在的对象,这造成了对象构造过程中的浪费。如果是关注性能和资源的应用,此处就是一个需要改进的点。
我们假设这个类叫 ExpensiveClass 。
public class ExpensiveClass
{
public ExpensiveClass(string id)
{
Id = id; Console.WriteLine(
"Id: [" + id + "] called expensive methods " +
"which perhaps consume a lot of resources or time.");
} public string Id { get; set; }
}
类实例化的构造过程为什么昂贵可能有很多中情况,最简单的例子可以为:
- 访问了数据库,读取了数据,并缓存了数据。
- 访问了远程服务,读取了数据,并缓存了数据。
- 将磁盘中的数据加载到内存中。
改进方式1:使用Proxy模式
我们可以使用 Proxy 模式来包装它,通过 Proxy 中间的代理过程来隔离对对象的直接创建。
public class ExpensiveClassProxy
{
private string _expensiveClassId;
private ExpensiveClass _expensiveClass; public ExpensiveClassProxy(string expensiveClassId)
{
_expensiveClassId = expensiveClassId;
} public ExpensiveClass XXXMethod()
{
if (_expensiveClass == null)
{
lock (_expensiveClass)
{
if (_expensiveClass == null)
{
_expensiveClass = new ExpensiveClass(_expensiveClassId);
}
}
}
return _expensiveClass;
}
}
改进方式2:使用Lazy<T>模式
这种方式简单易用,并且同样解决了问题。
ConcurrentDictionary<string, Lazy<ExpensiveClass>> dict2
= new ConcurrentDictionary<string, Lazy<ExpensiveClass>>(); string key2 = "";
ExpensiveClass value2 = dict2.GetOrAdd(
key2,
(k) => new Lazy<ExpensiveClass>(
() => new ExpensiveClass(k)))
.Value;
在并行的条件下,同样也存在构造了一个 Lazy<ExpensiveClass> 然后丢弃的现象,所以这种方式是建立在,构造 Lazy<T> 对象的成本要小于构造 ExpensiveClass 的成本。
改进ConcurrentDictionary并行使用的性能的更多相关文章
- Java 8 (6) Stream 流 - 并行数据处理与性能
在Java 7之前,并行处理集合非常麻烦.首先你要明确的把包含数据的数据结构分成若干子部分,然后你要把每个子部分分配一个独立的线程.然后,你需要在恰当的时候对他们进行同步来避免竞争,等待所有线程完成. ...
- 《Java 8 in Action》Chapter 7:并行数据处理与性能
在Java 7之前,并行处理数据集合非常麻烦.第一,你得明确地把包含数据的数据结构分成若干子部分.第二,你要给每个子部分分配一个独立的线程.第三,你需要在恰当的时候对它们进行同步来避免不希望出现的竞争 ...
- SQL并行与否的性能差异
比较两种代码,核心代码相同,其中一个使用变量保存查询出的结果,另一个直接输出.使用同一变量时,强迫SQL放弃了并行,使用了循环. 测试结果 表'#1699586C'.扫描计数1,逻辑读取186 次 ...
- Java 8并行流的性能陷阱
并行化流被分成多个块,每个块独立处理,结果在最后汇总. CPU密集型代码如下: private long countPrimes(int max) { return range(1, max) ...
- .NET 7 性能改进 -- 至今为止最快的.NET平台
2022年8月31日 Stephen Toub 发布的关于 .NET 7 性能改进的博客, 核心主题是 .NET 7 速度很快. 这篇博客非常的长,我尝试将它拷贝到Word 里,拷贝的时间都花了几分钟 ...
- .NET性能系列文章一:.NET7的性能改进
这些方法在.NET7中变得更快 照片来自 CHUTTERSNAP 的 Unsplash 欢迎阅读.NET性能系列的第一章.这一系列的特点是对.NET世界中许多不同的主题进行研究.比较性能.正如标题所说 ...
- SQL Server 2016中In-Memory OLTP继CTP3之后的新改进
SQL Server 2016中In-Memory OLTP继CTP3之后的新改进 转译自:https://blogs.msdn.microsoft.com/sqlserverstorageengin ...
- 【转发】关于Java性能的9个谬论
转载请注明出处,感谢大家的支持!本文来自优优码:http://www.uucode.net/201502/9%e4%b8%aa%e8%b0%ac%e8%ae%ba Java的性能有某种黑魔法之称.部分 ...
- Java性能调优
一.JVM内存模型及垃圾收集算法 1.根据Java虚拟机规范,JVM将内存划分为: New(年轻代) Tenured(年老代) 永久代(Perm) 其中New和Tenured属于堆内存,堆内存会从JV ...
随机推荐
- PLAN表
用得较多的PLAN表有以下三个ABPPMGR:MANUFACTURINGPLN.SHIPMENTPLAN.PROCUREMENTPLAN .这三个表都是执行StartFP中的exportFP进行数据导 ...
- 自动获取socket链接状态
C# TcpClient在连接成功后无法检测连接状态,即使对方关闭了网络连接.以下扩展可检测连接状态: static class TcpClientEx { public static bool Is ...
- [Swift]基础
[Swift]基础 一, 常用变量 var str = "Hello, playground" //变量 let str1="Hello xmj112288" ...
- cms替换主页的步骤
cms替换主页的步骤 .先做好静态页面: .在D:\wamp\www\phpcms\install_package\phpcms\templates文件夹下建新的文件夹tianqiwangluo(项目 ...
- 《机器学习实战》学习笔记——第2章 KNN
一. KNN原理: 1. 有监督的学习 根据已知事例及其类标,对新的实例按照离他最近的K的邻居中出现频率最高的类别进行分类.伪代码如下: 1)计算已知类别数据集中的点与当前点之间的距离 2)按照距离从 ...
- X Window 设定介绍
在 Unix Like 上面的图形用户接口 (GUI) 被称为 X 或 X11 X11 是一个『软件』而不是一个操作系统: X11 是利用网络架构来进行图形接口的执行与绘制: 最著名的 X 版本为 X ...
- Selenium2+python自动化13-多窗口、句柄(handle)
前言 有些页面的链接打开后,会重新打开一个窗口,对于这种情况,想在新页面上操作,就得先切换窗口了.获取窗口的唯一标识用句柄表示,所以只需要切换句柄,我们就能在多个页面上灵活自如的操作了. 本篇以打开百 ...
- Hdu OJ 5884-Sort (2016 ACM/ICPC Asia Regional Qingdao Online)(二分+优化哈夫曼)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5884 题目大意:有n个有序的序列,对于第i个序列有ai个元素. 现在有一个程序每次能够归并k个序列, ...
- 使用spring 4.0 + maven 构建超简单的web项目
一.需求 使用spring去管理web项目,是目前非常流行的一种思路,本文将介绍使用maven+spring 4.0.2 来构建一个简单的web项目. 二.实现 1.新建一个maven项目,如下图所示 ...
- linux桌面环境gnome,kde,xfce,lxde 使用比较(转)
Linus Torvalds大神前几日在 Google+上表示,GNOME 3"无可容忍的凌乱",改投Xfce桌面环境.下面就GNOME, KDE, XFCE和 LXDE略作比较. ...