CSDN-CSDN社区-.NET技术-ASP.NET

收藏 [推荐] 【300分放分】一个世界上最懒惰的程序员写的Cache也能让你的复杂计算程序(数据库程序)大大提高速度[问题点数:300,结帖人:sp1234]

  • sp1234
  • (龙芯偷盗8年终于“合理”购买了)
  • 等 级:
  • 结帖率:
楼主发表于:2008-11-24 19:08:16
仔细模拟一下你的数据库程序,你有没有发现在计算时(特别是多用户计算时)经常重复读取数据库数据?!这是数据库处理程序的性能的最主要的杀手。

有些人说在写程序之前应该把算法想好,使得数据记录成批地、一次性地读取。但是这实际上往往不可能,因为复杂的程序贴近逻辑流程才清晰可维护。更何况这也不能解决多用户访问的情况。最好,我们根本不用在写程序时去考虑数据是否会被重复读取从而改变程序流程,但是又能自然而然地防止重复读取数据库。当对计算过程进行优化,而又不想破坏逻辑清晰性的时候,当然就是要依靠简单的Cache —— 对象只要能够缓存几秒钟就好。

下面我这里写一个世界上最懒惰的程序员使用.net写的一个最简单的Cache,但是它往往可以让复杂的计算程序大大提高计算速度。

C# code
using System; using System.Collections.Generic; namespace DomainBase { public class ObjectCache { //Dictionary<K,T> 会自动维护一个空链表来保存不用的单元。 //这里,使用被缓存对象的“弱引用”,允许这些对象被垃圾回收。 private Dictionary<string, WeakReference> Buffer = new Dictionary<string, WeakReference>(); public object this[string key] { get { WeakReference ret; if (Buffer.TryGetValue(key, out ret) && ret.IsAlive) return ret.Target; else return null; } set { WeakReference ret; if (Buffer.TryGetValue(key, out ret)) ret.Target = value; else Buffer.Add(key, new WeakReference(value)); } } public void Remove(string key) { Buffer.Remove(key); } } }


这就是最简单的Cache。例如:

public Class User
{
    static ObjectCache Buffer=new ObjectCache();

    public static GetUser(string id)
    {
      User ret=Buffer[id];
      if(ret==null)
      {
            ret=读取数据库产生User对象(id);
            Buffer[id]=ret;
      }
      return ret;
    }
.....

这里,在一个Dictionary <K,T>结构字典中保存了对象的key以及对象的“弱引用”。这样,当内存不足时GC会照样去释放被缓存的对象。当我们需要将对象在几秒钟内进行缓存时,使用这个最简单的Cache很有用。

.net framework中有非常多非常多的东西需要程序员去了解,不要仅仅抱着那些空洞、不实惠的“放之四海而皆准”的大部头的著作,有时间要多读一些实际地分析 .net framework 系统本身的方面的资料。在每一个技术中都可以找对一两个细节,这个细节就像掌握DNA技术一样能够让你不但扩展原理而且通过动手能力得到巨大实惠。
回复次数:636
#1楼 得分:30回复于:2008-11-24 19:10:37
  • yfqvip用户头像
  • yfqvip
  • (当爱已成往事)
  • 等 级:
#2楼 得分:30回复于:2008-11-24 19:11:59
  • yfqvip用户头像
  • yfqvip
  • (当爱已成往事)
  • 等 级:
#3楼 得分:0回复于:2008-11-24 19:18:24
很简,很实用。
  • sp1234用户头像
  • sp1234
  • (龙芯偷盗8年终于“合理”购买了)
  • 等 级:
#4楼 得分:0回复于:2008-11-24 19:18:41
程序示例中可以写

User ret=Buffer[id] as User;

类型转换。
#5楼 得分:30回复于:2008-11-24 19:28:06
  • mjjzg用户头像
  • mjjzg
  • (mjjzg)
  • 等 级:
#6楼 得分:30回复于:2008-11-24 19:34:07
#7楼 得分:30回复于:2008-11-24 19:37:06
  • iuhxq用户头像
  • iuhxq
  • (小灰(Svn服务器))
  • 等 级:
#8楼 得分:0回复于:2008-11-24 19:37:26
学习呀
  • hztltgg用户头像
  • hztltgg
  • (我想我是风)
  • 等 级:
#9楼 得分:30回复于:2008-11-24 19:41:35
  • jjt009用户头像
  • jjt009
  • (平凡)
  • 等 级:
#10楼 得分:30回复于:2008-11-24 19:45:11
#11楼 得分:30回复于:2008-11-24 19:47:08
#12楼 得分:30回复于:2008-11-24 20:02:28
  • cj205用户头像
  • cj205
  • (阡陌之谜)
  • 等 级:
#13楼 得分:30回复于:2008-11-24 20:04:59
#14楼 得分:0回复于:2008-11-24 20:13:55
支持!!
  • oyiboy用户头像
  • oyiboy
  • (webCoder)
  • 等 级:
#15楼 得分:0回复于:2008-11-24 20:16:33
其实我总是一厢情愿的去认为cache会让程序占用内存数字变大。让用户对我的系统产生饭桶(吃太多内存)的感觉。
之前也用过cache来作东西,但是出现一种很奇怪的现象。某代码如下:
C# code
userdata udata=null; if (udata==null) { if(cache.userdata==null) { cache.userdata=new userdata(nowuserid); } udata=cache.userdata; } return udata.name;


啊,以上代码居然在return udata.name是提示udata==null,真是百思不得其解。后来用户催着出补丁,结果被我改成这样了
C# code
userdata udata=null; while (udata == null) { if(cache.userdata==null) { cache.userdata=new userdata(nowuserid); } udata=cache.userdata; } return udata.name;


当时真的很是纳闷呢。cache丢失得也忒快了点
  • culture9用户头像
  • culture9
  • (几年过去还是。。。)
  • 等 级:
#16楼 得分:0回复于:2008-11-24 20:33:36
小兵来学习
#17楼 得分:0回复于:2008-11-24 20:37:15
学习+收藏
  • antiking用户头像
  • antiking
  • (Q狼E行-吹雪留香一点红,孤城)
  • 等 级:
#18楼 得分:0回复于:2008-11-24 20:45:34
mark
#19楼 得分:0回复于:2008-11-24 20:48:44
有些晕

  • fanliang11用户头像
  • fanliang11
  • (以编程为兴趣,以盖茨为激励)
  • 等 级:
#20楼 得分:0回复于:2008-11-24 20:53:24
个人感觉比LZ先进哦。。而且有失效时间,还有LZ没有考虑到一种情况。。并发的情况就没有考虑。。有重大的BUG
C# code
using System; using System.Collections.Generic; using System.Collections; using System.Text; using System.Web; using System.Web.Caching; using System.Data; namespace test { /// <summary> /// M缓存类 /// </summary> public class CommonCache { #region 构造函数 /// <summary> /// 静态构造函数 /// </summary> static CommonCache() { } #endregion #region 属性定义 /// <summary> /// 失效时间单位为分钟 /// </summary> public static int LoseTime { set { mLoseTime = value; } } #endregion #region 公共方法 /// <summary> /// 获取值 /// </summary> /// <param name="pKey">键值名</param> /// <returns>返回键值</returns> public static object GetValue(object pKey) { object retValue = null; lock (mCache.SyncRoot) { try { if (mCache.ContainsKey(pKey)) { retValue=mCache[pKey]; IList<object> valueArr = (IList<object>)retValue; DateTime dt = Convert.ToDateTime(valueArr[0]); if (dt.CompareTo(DateTime.Now) < 0) { retValue = null; } else { retValue = valueArr[1]; } } else { retValue = null; } } catch (Exception e) { retValue = null; } } return retValue; } /// <summary> /// 设置值 /// </summary> /// <param name="pKey">键值名</param> /// <param name="pValue">键值</param> public static void SetValue(object pKey, object pValue) { IList<object> valueArr = new List<object>() ; valueArr.Add (DateTime.Now.AddMinutes(mLoseTime)); valueArr.Add ( pValue); lock (mCache.SyncRoot) { try { if (!mCache.ContainsKey(pKey)) { mCache.Add(pKey, valueArr); } else { mCache[pKey] = valueArr; } } catch (Exception e) { } } } #endregion #region 字段定义 /// <summary> /// 缓存对象 /// </summary> private static Hashtable mCache = new Hashtable(); /// <summary> /// 失效时间(单位:分钟) /// </summary> private static int mLoseTime = 60; #endregion } }
  • fanliang11用户头像
  • fanliang11
  • (以编程为兴趣,以盖茨为激励)
  • 等 级:
#21楼 得分:0回复于:2008-11-24 20:53:35
个人感觉比LZ先进哦。。而且有失效时间,还有LZ没有考虑到一种情况。。并发的情况就没有考虑。。有重大的BUG
C# code
using System; using System.Collections.Generic; using System.Collections; using System.Text; using System.Web; using System.Web.Caching; using System.Data; namespace test { /// <summary> /// M缓存类 /// </summary> public class CommonCache { #region 构造函数 /// <summary> /// 静态构造函数 /// </summary> static CommonCache() { } #endregion #region 属性定义 /// <summary> /// 失效时间单位为分钟 /// </summary> public static int LoseTime { set { mLoseTime = value; } } #endregion #region 公共方法 /// <summary> /// 获取值 /// </summary> /// <param name="pKey">键值名</param> /// <returns>返回键值</returns> public static object GetValue(object pKey) { object retValue = null; lock (mCache.SyncRoot) { try { if (mCache.ContainsKey(pKey)) { retValue=mCache[pKey]; IList<object> valueArr = (IList<object>)retValue; DateTime dt = Convert.ToDateTime(valueArr[0]); if (dt.CompareTo(DateTime.Now) < 0) { retValue = null; } else { retValue = valueArr[1]; } } else { retValue = null; } } catch (Exception e) { retValue = null; } } return retValue; } /// <summary> /// 设置值 /// </summary> /// <param name="pKey">键值名</param> /// <param name="pValue">键值</param> public static void SetValue(object pKey, object pValue) { IList<object> valueArr = new List<object>() ; valueArr.Add (DateTime.Now.AddMinutes(mLoseTime)); valueArr.Add ( pValue); lock (mCache.SyncRoot) { try { if (!mCache.ContainsKey(pKey)) { mCache.Add(pKey, valueArr); } else { mCache[pKey] = valueArr; } } catch (Exception e) { } } } #endregion #region 字段定义 /// <summary> /// 缓存对象 /// </summary> private static Hashtable mCache = new Hashtable(); /// <summary> /// 失效时间(单位:分钟) /// </summary> private static int mLoseTime = 60; #endregion } }
  • isline用户头像
  • isline
  • (缘清)
  • 等 级:
#22楼 得分:0回复于:2008-11-24 20:54:43
Cache使用时装箱与拆箱的资源损耗是不是和Session使用时的损耗差不多呢?
#23楼 得分:0回复于:2008-11-24 21:02:29
Mark && thanks
  • dzswej用户头像
  • dzswej
  • (鹰之旅途)
  • 等 级:
#24楼 得分:0回复于:2008-11-24 21:09:04
好贴 学习
  • fanliang11用户头像
  • fanliang11
  • (以编程为兴趣,以盖茨为激励)
  • 等 级:
#25楼 得分:0回复于:2008-11-24 21:09:11
引用 22 楼 isline 的回复:
Cache使用时装箱与拆箱的资源损耗是不是和Session使用时的损耗差不多呢?

用Session没搞错吧。。先搞清楚Session机制。。。
再搞清楚什么时候用Cache。。。你的专家分咋来的。。
#26楼 得分:0回复于:2008-11-24 21:11:25
以编程为兴趣,以盖茨为激励
  • IMAGSE用户头像
  • IMAGSE
  • (学技术,到csdn,随到随学,)
  • 等 级:
#27楼 得分:0回复于:2008-11-24 21:15:28
接分~
#28楼 得分:0回复于:2008-11-24 21:19:30
以编程为兴趣,以盖茨为激励
  • oyiboy用户头像
  • oyiboy
  • (webCoder)
  • 等 级:
#29楼 得分:0回复于:2008-11-24 21:30:48
引用 22 楼 isline 的回复:
Cache使用时装箱与拆箱的资源损耗是不是和Session使用时的损耗差不多呢?



听了这话我有点迷糊了,值类型有box/unbox的消耗,象是类没有这方面的消耗吧。而且值类型的消耗是因为在装箱时需要生成一个类来放这个结构所以才会有大的消耗,而类似乎本身就是一个类,只是简单的类型转换而以吧。sdk的原话是这样的

装箱和取消装箱都是需要大量运算的过程。对值类型进行装箱时,必须创建一个全新的对象。此操作所需时间可比赋值操作长 20 倍。取消装箱时,强制转换过程所需时间可达赋值操作的四倍。

天!!好象我又理解错东西了....
  • fanliang11用户头像
  • fanliang11
  • (以编程为兴趣,以盖茨为激励)
  • 等 级:
#30楼 得分:0回复于:2008-11-24 21:52:45
Dictionary 泛型实际上底层还是调用的Hashtable,所以效率会比Hashtable 低。。。不相信。。大家可以插入和单值查找的进行测试下。。。看下Dictionary 和Hashtable那个效率更高些。。
 对以字符串为主键的单值查找的优先选择 Hashtable 或者 Dictionary. 个人觉得如果只注重效率的话, Hashtable 更好一些,特别是在字符串较长时其效率几乎比Dictionary 快将近一倍。
#31楼 得分:0回复于:2008-11-24 21:54:06
学习下
  • sharpblade用户头像
  • sharpblade
  • (学习知识传播知识)
  • 等 级:
#32楼 得分:0回复于:2008-11-24 21:58:38
恩,有点用
#33楼 得分:0回复于:2008-11-24 22:04:04
受教了
弱引用学到了,不错
#34楼 得分:0回复于:2008-11-24 22:09:13
mark

先顶再看
  • sincor用户头像
  • sincor
  • (Sincor)
  • 等 级:
#35楼 得分:0回复于:2008-11-24 22:12:52
引用 12 楼 zshengli 的回复:
前辈  谢谢分享
#36楼 得分:0回复于:2008-11-24 22:16:26
受教了。马上改自己的网站!
  • lfzpf用户头像
  • lfzpf
  • (博观而约取,厚积而薄发)
  • 等 级:
#37楼 得分:0回复于:2008-11-24 22:16:31
学习了!
  • hubofly用户头像
  • hubofly
  • (幸福瞬间)
  • 等 级:
#38楼 得分:0回复于:2008-11-24 22:18:55
顶一下  关注
  • ccs02287用户头像
  • ccs02287
  • (空心兜兜)
  • 等 级:
  • 5

    3

#39楼 得分:0回复于:2008-11-24 22:23:26
学习下

  • computerfriend用户头像
  • computerfriend
  • (人之所以诸般痛苦,是应为太过于)
  • 等 级:
#40楼 得分:0回复于:2008-11-24 22:23:50
学习...
是用对象属性控制的吗!?
#41楼 得分:0回复于:2008-11-24 22:25:38
收了。
回头研究
#42楼 得分:0回复于:2008-11-24 22:26:16
学习```
#43楼 得分:0回复于:2008-11-24 22:26:42
接分~~  呵呵 学习!
陋习跟上~
  • fanliang11用户头像
  • fanliang11
  • (以编程为兴趣,以盖茨为激励)
  • 等 级:
#44楼 得分:0回复于:2008-11-24 22:28:22
LZ请考虑并发的情况。。
  • myqxue用户头像
  • myqxue
  • (叶子)
  • 等 级:
#45楼 得分:0回复于:2008-11-24 22:28:25
最近被缓存弄糊涂了,正需要这方面的知识,学习了
  • zhnzzy用户头像
  • zhnzzy
  • (学习中~~)
  • 等 级:
#46楼 得分:0回复于:2008-11-24 22:29:46
不错
#47楼 得分:0回复于:2008-11-24 22:33:23
在经常重复访问数据库的情况下,几秒钟的Cache的确可以使运算速度提高不少
  • firefoxxx用户头像
  • firefoxxx
  • (猪一样的队友)
  • 等 级:
#48楼 得分:0回复于:2008-11-24 22:35:47
缓存技巧  学习一下 目前正在学习怎么提高访问性能
#49楼 得分:0回复于:2008-11-24 22:37:39
厉害
#50楼 得分:0回复于:2008-11-24 22:38:58
学习...
相关问题
一个程序员的奋斗历程.(转)
C# PK VB.NET,来吧,到底谁更强.NET技术/ VB.NET - CSDN社区community ...