• 使用Dictionary做缓存的一些问题.


    在实际开发过程中,Dictionary是一种经常被用来做缓存的数据结构,既然是用来做缓存,那么不可避免的就要涉及到多线程的问题,如何来合理的使用,这是一个问题,这个问题与实际业务场景有很大关系,通常来说,会有这么几种场景

    1, 一次性写入,不再改变

    2, 存在写入与删除

    对于缓存来说,永远是读操作占了大部分,因此,必须要确保对于读来说,不会影响并发,这是首要的原则,对于那种在读的时候需要lock的必须否定,对于第一种场景,没什么可说的,直接使用Dictionary就行,Dictionary在内容不变的情况下,对于读操作是可以并发的,并且这种情况下读性能是最好的。

    对于第二种场景来说,又要做区分,需要根据缓存列表的预估长度以及写操作频繁度来选择,

    如果预估长度不大或者写操作不频繁,建议通过“不变列表”模式来实现,具体来说,在写操作的代码中,这样写

     1 //_lock为一个静态object,用来做lock操作
     2             //_dict为静态缓存的Dictionary对象
     3             lock(_lock)
     4             {
     5                 //通过ToDictionary浅拷贝出一个新的Dictionary对象
     6                 //这样可以保证原先的_dict对于读操作“不变”,使读操作不收任何并发影响
     7                 var copyDict =_dict.ToDictionary((kv) => kv.Key,(kv)=>kv.Value);
     8                 //这里做新增删除的动作
     9                 copyDict["key"] = "value";
    10                 //修改完成后重新为静态缓存赋值
    11                 _dict = copyDict;
    12             }

    这就是所谓的“不变列表”模式,从这里也可以看出,如果列表长度很大的话,其实每次执行浅拷贝的动作都会有不少的耗时,这个耗时是随着列表的长度线性增长的,这就是为什么这种模式适用于“预估长度不大或者写操作不频繁”这种场景。

    那如果预估长度很大或者写操作很频繁怎么办呢,这个使用就要用到框架中的并行字典了,也就是ConcurrentDictionary,这个是线程安全的字典类,因此可以像单线程操作一样去使用,它的内部已经做了多线程的处理了,唯一的缺点是,在读的时候,由于内部依然会有锁的动作,是不如“不变列表”模式的性能高的。

    以上就是使用Dictionary做缓存时要考虑的问题

  • 相关阅读:
    scss rem 转换函数
    URL Scheme —— 唤端媒介
    extend 对象继承
    [转载]jdk1.8垃圾回收器
    [转载]java高分局之jstat命令使用
    一个用消息队列 的人,不知道为啥用 MQ,这就有点尴尬
    context-param 监听器 过滤器 servlet 拦截器的区别
    springSecurity源码分析——DelegatingFilterProxy类的作用
    Spring Security的核心拦截器
    CAS之TICKET
  • 原文地址:https://www.cnblogs.com/rhwleo/p/6883165.html
Copyright © 2020-2023  润新知