C# 实现Lru缓存

news/2024/7/8 2:24:07 标签: c#, 缓存

C# 实现Lru缓存

LRU 算法全称是最近最少使用算法(Least Recently Use),是一种简单的缓存策略。
通常用在对象池等需要频繁获取但是又需要释放不用的地方。

代码实现的基本原理就是使用链表,当某个元素被访问时(Get或Set)就将该元素放到链表的头部或者尾部(根据用户自己定义规则即可)当达到了缓存的最大容量时对最不常使用的元素进行移除(移除的时候可以定义一系列的规则,用于判读如何移除,是否移除)

下面直接贴出来代码供大家参考

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;

namespace ET
{
    public class LruCache<TKey, TValue>: IEnumerable<KeyValuePair<TKey, TValue>>
    {
        private const int DEFAULT_CAPACITY = 255;

        private int capacity;
        private ReaderWriterLockSlim locker;
        private Dictionary<TKey, TValue> dictionary;
        private LinkedList<TKey> linkedList;
        private Func<TKey, TValue, bool> checkCanPopFunc;
        private Action<TKey, TValue> popCb;

        public LruCache(): this(DEFAULT_CAPACITY)
        {
        }

        public LruCache(int capacity)
        {
            this.locker = new ReaderWriterLockSlim();
            this.capacity = capacity > 0? capacity : DEFAULT_CAPACITY;
            this.dictionary = new Dictionary<TKey, TValue>(DEFAULT_CAPACITY);
            this.linkedList = new LinkedList<TKey>();
        }

        /// <summary>
        /// 设置检测什么条件可以释放
        /// </summary>
        /// <param name="func"></param>
        public void SetCheckCanPopCallBack(Func<TKey, TValue, bool> func)
        {
            this.checkCanPopFunc = func;
        }

        /// <summary>
        /// 设置如何释放
        /// </summary>
        /// <param name="action"></param>
        public void SetPopCallBack(Action<TKey, TValue> action)
        {
            this.popCb = action;
        }

        public TValue this[TKey t]
        {
            get
            {
                if (TryGet(t, out TValue val))
                    return val;
                throw new ArgumentException();
            }
            set
            {
                Set(t,value);
            }
        }

        public bool TryGet(TKey key, out TValue value)
        {
            this.locker.EnterUpgradeableReadLock();
            try
            {
                bool b = this.dictionary.TryGetValue(key, out value);
                if (b)
                {
                    this.locker.EnterWriteLock();
                    try
                    {
                        this.linkedList.Remove(key);
                        this.linkedList.AddFirst(key);
                    }
                    finally
                    {
                        this.locker.ExitWriteLock();
                    }
                }

                return b;
            }
            finally
            {
                this.locker.ExitUpgradeableReadLock();
            }
        }

        public void Set(TKey key, TValue value)
        {
            this.locker.EnterWriteLock();
            try
            {
                if (this.checkCanPopFunc != null)
                    this.MakeFreeSpace();

                this.dictionary[key] = value;
                this.linkedList.Remove(key);
                this.linkedList.AddFirst(key);
                //没有设置检测释放条件的话,容量超载了就移除
                if (this.checkCanPopFunc == null && this.linkedList.Count > this.capacity)
                {
                    this.dictionary.Remove(this.linkedList.Last.Value);
                    this.linkedList.RemoveLast();
                }
            }
            finally
            {
                this.locker.ExitWriteLock();
            }
        }

        public Dictionary<TKey, TValue> GetAll()
        {
            return this.dictionary;
        }
        
        public void Remove(TKey key)
        {
            this.locker.EnterWriteLock();
            try
            {
                this.dictionary.Remove(key);
                this.linkedList.Remove(key);
            }
            finally
            {
                this.locker.ExitWriteLock();
            }
        }
        
        public bool TryOnlyGet(TKey key, out TValue value)
        {
            bool b = this.dictionary.TryGetValue(key, out value);
            return b;
        }
        
        public bool ContainsKey(TKey key)
        {
            this.locker.EnterReadLock();
            try
            {
                return this.dictionary.ContainsKey(key);
            }
            finally
            {
                this.locker.ExitReadLock();
            }
        }
        
        public int Count
        {
            get
            {
                this.locker.EnterReadLock();
                try
                {
                    return this.dictionary.Count;
                }
                finally
                {
                    this.locker.ExitReadLock();
                }
            }
        }

        public int Capacity
        {
            get
            {
                this.locker.EnterReadLock();
                try
                {
                    return this.capacity;
                }
                finally
                {
                    this.locker.ExitReadLock();
                }
            }
            set
            {
                this.locker.EnterUpgradeableReadLock();
                try
                {
                    if (value > 0 && this.capacity != value)
                    {
                        this.locker.EnterWriteLock();
                        try
                        {
                            this.capacity = value;
                            while (this.linkedList.Count > this.capacity)
                            {
                                this.linkedList.RemoveLast();
                            }
                        }
                        finally
                        {
                            this.locker.ExitWriteLock();
                        }
                    }
                }
                finally
                {
                    this.locker.ExitUpgradeableReadLock();
                }
            }
        }
        
        public ICollection<TKey> Keys
        {
            get
            {
                this.locker.EnterReadLock();
                try
                {
                    return this.dictionary.Keys;
                }
                finally
                {
                    this.locker.ExitReadLock();
                }
            }
        }

        public ICollection<TValue> Values
        {
            get
            {
                this.locker.EnterReadLock();
                try
                {
                    return this.dictionary.Values;
                }
                finally
                {
                    this.locker.ExitReadLock();
                }
            }
        }
        
        public void Clear()
        {
            this.dictionary.Clear();
            this.linkedList.Clear();
        }
        
        private void MakeFreeSpace()
        {
            LinkedListNode<TKey> node = this.linkedList.Last;

            //检测最不常用的10个
            int max_check_free_times = 10; //最大检测空闲次数
            int cur_check_free_time = 0; //当前检测空闲次数

            while (this.linkedList.Count + 1 > this.capacity)
            {
                if (node == null)
                    break;

                LinkedListNode<TKey> tuple_prev = node.Previous;
                if (this.checkCanPopFunc == null || this.checkCanPopFunc(node.Value, this.dictionary[node.Value]))
                {
                    //可以释放
                    var value = this.dictionary[node.Value];
                    this.dictionary.Remove(node.Value);
                    this.linkedList.RemoveLast();
                    this.popCb?.Invoke(node.Value, value);
                }
                else
                {
                    cur_check_free_time++;
                    if (cur_check_free_time >= max_check_free_times)
                    {
                        break;
                    }
                }

                node = tuple_prev;
            }
        }

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            foreach (var item in this.dictionary)
            {
                yield return item;
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            foreach (var item in this.dictionary)
            {
                yield return item;
            }
        }
    }
}

http://www.niftyadmin.cn/n/5251428.html

相关文章

操作系统考研笔记(王道408)

文章目录 前言计算机系统概述OS的基本概念OS的发展历程OS的运行机制OS体系结构OS引导虚拟机 进程和线程进程和线程基础进程进程状态进程控制进程通信线程线程实现 CPU调度调度的层次进程调度细节调度算法评价指标批处理调度算法交互式调度方法 同步与互斥基本概念互斥互斥软件实…

2020年第九届数学建模国际赛小美赛A题自由泳解题全过程文档及程序

2020年第九届数学建模国际赛小美赛 A题 自由泳 原题再现&#xff1a; 在所有常见的游泳泳姿中&#xff0c;哪一种最快&#xff1f;哪个冲程推力最大&#xff1f;在自由泳项目中&#xff0c;游泳者可以选择他们的泳姿&#xff0c;他们通常选择前面的爬行。然而&#xff0c;游泳…

simulinkveristandlabview联合仿真环境搭建

目录 开篇废话 软件版本 明确需求 软件安装 matlab2020a veristand2020 R4 VS2017 VS2010 软件安装验证 软件资源分享 开篇废话 推免之后接到的第一个让人难绷的活&#xff0c;网上开源的软件资料和成功的案例很少&#xff0c;查来查去就那么几篇&#xff0c;而且版本…

mysql 语言学习

整理了一下 mysql 操作语言&#xff0c;不是很全&#xff0c;部分地方也许需要修改&#xff0c;先放上来&#xff0c;有时间再慢慢完善。 一、数据库操作 连接数据库 $ sudo mysql [-h ip] -u root -p [-P 3306] 初始化数据库 $ mysql_secure_installation备份数据库 # 备…

用perl查找文件夹中的所有文件和目录

查找文件夹中的文件和目录是一个很常见的操作&#xff0c;使用perl的File::Find模块可以很方便的实现。首先使用perldoc File::Find 查看一下文档: 这个核心的就是文档中描述的回调函数。我们举一个实际的例子&#xff0c;一个空的git仓库为例&#xff0c;下面的脚本用于查找…

基于springboot + vue 购物推荐系统

qq&#xff08;2829419543&#xff09;获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;springboot 前端&#xff1a;采用vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xf…

vue,uniapp的pdf等文件在线预览

vue&#xff0c;uniapp文件在线预览方案&#xff0c;用了个稍微偏门一点的方法实现了 通过后端生成文件查看页面&#xff0c;然后前端只要展示这个网页就行&#xff0c;uniapp就用web-view来展示&#xff0c;后台系统就直接window.open()打开就行 示例查看PDF文件&#xff0c;…

C#注册表技术及操作

目录 一、注册表基础 1.Registry和RegistryKey类 &#xff08;1&#xff09;Registry类 &#xff08;2&#xff09;RegistryKey类 二、在C#中操作注册表 1.读取注册表中的信息 &#xff08;1&#xff09;OpenSubKey()方法 &#xff08;2&#xff09;GetSubKeyNames()…