博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

线程、同步与锁——EventWaitHandle实战数据缓存

Posted on 2007-02-08 10:18  城市兔子  阅读(7810)  评论(8编辑  收藏  举报
        前两天总结了LockMonitor)和Mutex这样的锁,现在继续总结EventWaitHandle。呵呵,各位看客们注意了,我写的东西只是总结的经验想和大家分享,没有教人的意思,写的不对的地方还望大家指正。

         关于ManualResetHandleAutoResetHandle这两个东西的介绍我看就免了吧,用WaitOne()阻塞线程,用Set()来通知阻塞。网上的帖子很多很多,大可baidu或者google一下,还需要弄清楚他们的区别。值得一提的是他们的祖辈WaitHandle里面的方法:WaitAll(),WaitAny()等等这样的静态方法来控制线程的走向,很是得心应手的。

         还是先来个实例,在某些情况下我们需要数据库缓存,比如需要频繁的查找查某个表,而对他的操作却不多(比如说论坛里的分级类别),这样的话一次一次的查询数据库,性能上的损失的补偿失。这些东西要是能维护在内存中就是比较好了,而现在的题目就是如何设计这样的数据缓存。

         初始的算法大家都会想到,在查询数据库之前先查询缓存中是否有相应的数据,没有再查询数据库。然而WaitHandle里面的WaitAny()却为我们提供了额外的灵感,如果让查询缓存和查询数据库同时进行,那个先得出结果,先得到缓存的返回值,就使用缓存中的数据,要么就拿数据库的数据。这样的效率又比第一种算法优化一些。

         具体如何实现呢:

         

    public DataSet ExecuteSelect(string sql)
        {
            
//创建缓存线程生命两个ManualResetEvent
            
//创建缓存线程
            Thread threadCache = new Thread(ExecuteSelectWithCache);
            
//创建数据查询线程
            Thread threadDatabase = new Thread(ExecuteSelectWithDatabase);
            
//启动两个线程
            threadDatabase.Start(bagDatabase);
            threadCache.Start(bagCache);
            
//等待任意一个返回
            WaitHandle.WaitAny(Events);
            
//判断返回
            
//如果数据查询出来则取消缓存查询,返回数据库数据
            threadCache.Abort();
            
return bagDatabase.Dataset;
            
//如果缓存查询出来则取消数据查询,返回缓存中数据
            threadDatabase.Abort();
            
return bagCache.Dataset;
        }
        
        
public void ExecuteSelectWithCache(Object obj)
        {
            
//从缓存中查询数据
             ((DataBag)obj).Event.Set();
        }
        
public void ExecuteSelectWithDatabase(Object obj)
        {
            
//从数据库中查询数据
                ((DataBag)obj).Event.Set();
        }



         这样的好处,显儿意见得,两个线程同时来执行,谁快用谁的结果,也就省去了等待缓存查找结束后再来去查找数据库,我们把一个串行的结构变成了并行的结构。而这种线程阻塞和执行的核心在于WaitHandle.WaitAny().

来看看偶乱画的流程图:


OK
,我写这么的多东西,只是说明以下ManualResetEvent如何应用到实践中去,另外也说明了一种算法,很多时候,我们程序里面需要并行做事,而不仅仅是一条线下来。也就是说这样的算法不仅仅用在数据缓存中。

数据缓存


         PS:这仅仅是一个玩具而已,实际应用还需要很多改进的地方,缓存的策略,过期的时间,以及如何更加安全,等等。