无缝缓存读取简化:仅Lambda表达式传递委托

简介: 之前写了一篇:无缝的缓存读取:双存储缓存策略,其中使用了两个存储地址交替提供缓存数据。 在其中用了两个存储指针转换以达到无缝读取缓存,在Cat Chen一语提醒之后,想了一想:的确是没有必要在缓存中使用两个存储指针的,其实一个存储地址,只要保证写入时在其它线程就可以。

之前写了一篇:无缝的缓存读取:双存储缓存策略,其中使用了两个存储地址交替提供缓存数据。

在其中用了两个存储指针转换以达到无缝读取缓存,在Cat Chen一语提醒之后,想了一想:的确是没有必要在缓存中使用两个存储指针的,其实一个存储地址,只要保证写入时在其它线程就可以。

更改存储介质至以下两个属性:

namespace CHCache {
    /// <summary>
    /// 缓存介质
    /// </summary>
    public class Medium {
        /// <summary>
        /// 存储区
        /// </summary>
        public object Store { get; set; }
        /// <summary>
        /// 是否正在更新
        /// </summary>
        public bool IsUpdating { get; set; }
    }
}

这里存储区用于存储要缓存的实体内容,而IsUpdating则标识其是否正在更新。

对于缓存类,则更改了写入和读取方式。

/*
 * http://www.cnblogs.com/chsword/
 * chsword
 * Date: 2009-3-31
 * Time: 17:00
 * 
 */
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;

namespace CHCache {
    /// <summary>
    /// 双存储的类
    /// </summary>
    public class DictionaryCache : IEnumerable {
        /// <summary>
        /// 在此缓存构造时初始化字典对象
        /// </summary>
        public DictionaryCache() {
            Store = new Dictionary<string, Medium>();
        }
        public void Add(string key, Func<object> func) {
            if (Store.ContainsKey(key)) {//修改,如果已经存在,再次添加时则采用其它线程
                var elem = Store[key];
                if (elem.IsUpdating) return;  //正在写入未命中
                var th = new ThreadHelper(elem, func);
                var td = new Thread(th.Doit);
                td.Start();
            }
            else {//首次添加时可能也要读取,所以要本线程执行
                Console.WriteLine("Begin first write");
                Store.Add(key, new Medium { Store = func() });
                Console.WriteLine("End first write");
            }

        }
        /// <summary>
        /// 读取时所用的索引
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public object this[string key] {
            get {
                if (!Store.ContainsKey(key)) return null;
                var elem = Store[key];
                return elem.Store;
            }
        }
        Dictionary<string, Medium> Store { get; set; }
        public IEnumerator GetEnumerator() {
            return ((IEnumerable)Store).GetEnumerator();
        }
    }
}

这里在添加时只控制了首次写入缓存在主线程,而读取时则直接读取缓存内容。

而线程辅助类也进行了简化,仅将其执行并写入就好了,抛出线程完全由DictionaryCache控制。

using System;
namespace CHCache {
    /// <summary>
    /// 一个线程Helper,用于帮助多抛出线程时传递参数
    /// </summary>
    public class ThreadHelper {
        Func<object> Fun { get; set; }
        Medium Medium { get; set; }
        /// <summary>
        /// 通过构造函数来传递参数
        /// </summary>
        /// <param name="m"></param>
        /// <param name="fun"></param>
        public ThreadHelper(Medium m, Func<object> fun) {
            Medium = m;
            Fun = fun;
        }
        /// <summary>
        /// 线程入口,ThreadStart委托所对应的方法
        /// </summary>
        public void Doit() {
            Medium.IsUpdating = true;
            Console.WriteLine("Begin write.");
            var ret = Fun.Invoke();
            Medium.Store = ret;
            Console.WriteLine("End write.");
            Medium.IsUpdating = false;
        }
    }
}

其实有的时候思考问题还是不由自主的向着自己的经验方向刻意安排,这样通常把问题搞复杂了。

还好有园子里的朋友帮助,才简单的解决了问题,这样的由简至繁,再由繁衍至简的过程其实在实际开发中发生的还真不少。

 

目录
相关文章
|
18天前
|
缓存 NoSQL 网络安全
【Azure Redis 缓存】Azure Redis服务开启了SSL(6380端口), PHP如何访问缓存呢?
【Azure Redis 缓存】Azure Redis服务开启了SSL(6380端口), PHP如何访问缓存呢?
|
18天前
|
缓存 NoSQL Redis
【Azure Redis 缓存】Redission客户端连接Azure:客户端出现 Unable to send PING command over channel
【Azure Redis 缓存】Redission客户端连接Azure:客户端出现 Unable to send PING command over channel
|
18天前
|
存储 缓存 NoSQL
【Azure Redis 缓存】关于Azure Cache for Redis 服务在传输和存储键值对(Key/Value)的加密问题
【Azure Redis 缓存】关于Azure Cache for Redis 服务在传输和存储键值对(Key/Value)的加密问题
|
18天前
|
缓存 NoSQL Redis
【Azure Redis 缓存】Redis 连接失败
【Azure Redis 缓存】Redis 连接失败
|
18天前
|
缓存 NoSQL 网络协议
【Azure Redis 缓存】Lettuce 连接到Azure Redis服务,出现15分钟Timeout问题
【Azure Redis 缓存】Lettuce 连接到Azure Redis服务,出现15分钟Timeout问题
【Azure Redis 缓存】Lettuce 连接到Azure Redis服务,出现15分钟Timeout问题
|
14天前
|
缓存 NoSQL Java
Redis深度解析:解锁高性能缓存的终极武器,让你的应用飞起来
【8月更文挑战第29天】本文从基本概念入手,通过实战示例、原理解析和高级使用技巧,全面讲解Redis这一高性能键值对数据库。Redis基于内存存储,支持多种数据结构,如字符串、列表和哈希表等,常用于数据库、缓存及消息队列。文中详细介绍了如何在Spring Boot项目中集成Redis,并展示了其工作原理、缓存实现方法及高级特性,如事务、发布/订阅、Lua脚本和集群等,帮助读者从入门到精通Redis,大幅提升应用性能与可扩展性。
33 0
|
18天前
|
缓存 NoSQL Redis
【Azure Redis 缓存】使用StackExchange.Redis,偶发ERROR - Timeout performing HSET (15000ms)
【Azure Redis 缓存】使用StackExchange.Redis,偶发ERROR - Timeout performing HSET (15000ms)
|
18天前
|
缓存 NoSQL Java
【Azure Redis 缓存】示例使用 redisson-spring-boot-starter 连接/使用 Azure Redis 服务
【Azure Redis 缓存】示例使用 redisson-spring-boot-starter 连接/使用 Azure Redis 服务
|
9天前
|
缓存 NoSQL 关系型数据库
MySQL与Redis缓存一致性的实现与挑战
在现代软件开发中,MySQL作为关系型数据库管理系统,广泛应用于数据存储;而Redis则以其高性能的内存数据结构存储特性,常被用作缓存层来提升数据访问速度。然而,当MySQL与Redis结合使用时,确保两者之间的数据一致性成为了一个重要且复杂的挑战。本文将从技术角度分享MySQL与Redis缓存一致性的实现方法及其面临的挑战。
30 2