c# 一种缓存模板
在很多项目中,尤其是服务端,我们需要临时缓存一些数据,对于完整的我就不说了。主要的保持方法有:
1.大型数据库
2.缓存组件
3.文件(按照自己定义的格式存储)
4.一些缓存数据库(sqlte,h2,mongdb,redis等)
5.自定义的缓存方法。
这里我主要说说第5种方法,自定义类
首先我们定义一个泛型模板,用于存储真正的数据。
public class BaseBuffer<T>
{
/// <summary>
/// 真实数据对象
/// </summary>
public T Data { get; set; }
/// <summary>
/// 使用的时间
/// </summary>
public DateTime DateTime { get; set; }
//缓存丢失清理数据
public virtual void Dispose()
{
}
/// <summary>
/// 重置
/// </summary>
public virtual void Reset()
{
}
}
类似这样一个结构。
在存储时,我们需要一个类来管理,也就是缓存池的对象。
public class BufferPool<T>
{
/// <summary>
/// 缓存结构
/// </summary>
protected Stack<BaseBuffer<T>> buffers = new Stack<BaseBuffer<T>>(100);
private readonly object lock_obj = new object();
private int useNum = 0;//当前缓存使用
private volatile bool isRun = false;//已经启动运算
private int[] record = null;//记录
protected int waitTime = 20;//计算的分钟时间
private int index = 0;//索引计算
private int maxNum = 0;//最近一段时间最大使用
private int havNum = 0;//已经创建的缓存
private int minWaitTime = 100;//
private int maxBufferNum = int.MaxValue;
public BufferPool()
{
record = new int[waitTime];
}
/// <summary>
/// 设置运行的最大值
/// </summary>
public int MaxBufferSize { get { return maxBufferNum; } set { maxBufferNum = value; } }
/// <summary>
/// 初始化缓存对象
/// </summary>
/// <param name="initNum"></param>
public void InitPool(int initNum = 10)
{
if (initNum > 0)
{
for (int i = 0; i < initNum; i++)
{
buffers.Push(Create());
}
}
}
/// <summary>
/// 刷新
/// </summary>
private void RefreshCount()
{
if(isRun)
{
return;
}
isRun = true;
Task.Factory.StartNew(() =>
{
Thread.Sleep(60000);//1分钟
//
record[index] = useNum;
index++;
if(index%waitTime==0)
{
//监测waitTime分钟内没有使用的
lock (lock_obj)
{
var bufs= buffers.ToArray();
buffers.Clear();
foreach(var buf in bufs)
{
if((DateTime.Now-buf.DateTime).TotalMinutes<waitTime)
{
buffers.Push(buf);
}
else
{
buf.Dispose();
}
}
//
int sum = 0;
int avg = 0;
for(int i=0;i<record.Length;i++)
{
sum += record[i];
}
//计算时间内的平均值
avg = sum / record.Length;
//如果当前使用小于平均值,则最多只保留平均值个数
//说明当前使用可能在下降
if(useNum<avg&&buffers.Count>avg)
{
int num = buffers.Count - avg;
for (int i=0;i<num;i++)
{
var buf= buffers.Pop();
buf.Dispose();//不使用时释放
}
}
if(useNum>avg&&useNum>maxNum&&buffers.Count> maxNum)
{
//当前使用大于平均值,并且大于最近的最大值,说明再继续增加可能
//那就以最大缓存值为准
int num = buffers.Count - avg;
for (int i = 0; i < num; i++)
{
var buf = buffers.Pop();
buf.Dispose();//不使用时释放
}
}
}
}
isRun = false;
});
}
/// <summary>
/// 创建缓存对象
/// </summary>
/// <returns></returns>
public virtual BaseBuffer<T> Create()
{
Interlocked.Increment(ref havNum);
return new BaseBuffer<T>();
}
/// <summary>
/// 获取缓存对象
/// </summary>
/// <returns></returns>
public BaseBuffer<T> GetBuffer()
{
lock (lock_obj)
{
try
{
if (useNum < havNum)
{
//正在使用的小于已经创建的缓存
BaseBuffer<T> cache = buffers.Pop();
cache.DateTime = DateTime.Now;
useNum++;
this.RefreshCount();
return cache;
}
else if(havNum<maxBufferNum)
{
return Create();
}
else
{
return null;
}
}
catch
{
return Create();
}
}
}
/// <summary>
/// 超时获取数据
/// </summary>
/// <param name="waitTime">等待时间(毫秒)</param>
/// <param name="buffer">获取的buffer对象</param>
/// <returns>获取成功</returns>
public bool TryGetBuffer(int waitTime=0, out BaseBuffer<T> buffer)
{
buffer = null;
if(waitTime<1)
{
if((buffer = GetBuffer())==null)
{
return false;
}
else
{
return true;
}
}
else
{
int sleepTime = 0;
int sum = 0;
if (waitTime < minWaitTime)
{
sleepTime = waitTime;
}
else
{
sleepTime = 100;
}
while ((buffer = GetBuffer()) == null)
{
Thread.Sleep(sleepTime);
sum += sleepTime;
if (sum > waitTime)
{
break;
}
}
if(buffer==null)
{
//最后再获取一次
buffer = GetBuffer();
if(buffer==null)
{
return false;
}
else
{
return true;
}
}
else
{
return true;
}
}
}
/// <summary>
/// 获取一组缓存
/// </summary>
/// <param name="num"></param>
/// <returns></returns>
public virtual List<BaseBuffer<T>> GetCacheBuffers(int num)
{
List<BaseBuffer<T>> list = new List<BaseBuffer<T>>(num);
for(int i=0;i<num;i++)
{
list.Add(GetBuffer());
}
return list;
}
/// <summary>
/// 缓存释放
/// </summary>
/// <param name="client"></param>
public void Free(BaseBuffer<T> client)
{
lock (lock_obj)
{
useNum--;
buffers.Push(client);
}
}
}
一看就懂,不懂就完全弄到你的VS2017上面看看。
其实主要是回收缓存对象。获取对象,获取时提供了2个方法,直接获取以及有时间等待的。
刷新统计方法主要是用来动态平衡的。以20分钟为粒度。计算平均值,动态释放一些不需要的。
为什么使用的是Stack?
因为它是先进后出,这样如果有buffer一段时间没有使用,则它一直在尾部,例如:有100个buffer,一段时间只有了80个,另外20个就一直不会使用,这样在启动线程监测buffer时,就知道你有20个一直没有用,于是这20个算超时没有使用的,直接释放。
另外一类自定义缓存实现,推荐博文,我也集成到了我的项目模板中。
我自己的实现已经传到git,地址与前面博文提供的地址一样,项目名称是CacheBuffer
https://www.cnblogs.com/ylsforever/p/6511000.html
https://blog.csdn.net/niss/article/details/8764738
c# 一种缓存模板的更多相关文章
- Django中提供的6种缓存方式
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用: 缓存,缓存将一个某个views的返回值保存至内存或者memcache中, ...
- Django的几种缓存的配置
1.缓存的简介 在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面. 当一个网站的用户访问量很大的时候,每一次的的后台操作,都会 ...
- KVM几种缓存模式
原文在这里: http://pic.dhe.ibm.com/infocenter/lnxinfo/v3r0m0/index.jsp?topic=%2Fliaat%2Fliaatbpkvmguestca ...
- --@angularJS--模板加载之缓存模板demo
不用缓存模板的写法如下: 1.index.html: <!DOCTYPE HTML><html ng-app="app"><head> & ...
- CacheConcurrencyStrategy五种缓存方式
CacheConcurrencyStrategy有五种缓存方式: CacheConcurrencyStrategy.NONE,不适用,默认 CacheConcurrencyStrategy.REA ...
- 微软BI 之SSIS 系列 - Lookup 组件的使用与它的几种缓存模式 - Full Cache, Partial Cache, NO Cache
开篇介绍 先简单的演示一下使用 Lookup 组件实现一个简单示例 - 从数据源表 A 中导出数据到目标数据表 B,如果 A 数据在 B 中不存在就插入新数据到B,如果存在就更新B 和 A 表数据保持 ...
- angular 缓存模板 ng-template $templateCache
由于浏览器加载html模板是异步加载的,如果加载大量的模板会拖慢网站的速度,这里有一个技巧,就是先缓存模板. 使用angular缓存模板主要有三种方法: 方法一:通过script标签引入 <sc ...
- java中常用的几种缓存类型介绍
在平时的开发中会经常用到缓存,比如locache.redis等,但一直没有对缓存有过比较全面的总结.下面从什么是缓存.为什么使用缓存.缓存的分类以及对每种缓存的使用分别进行分析,从而对缓存有更深入的了 ...
- 深入理解HTTP协议及原理分析之缓存(3种缓存机制)
3.2 缓存的实现原理 3.2.1什么是Web缓存 WEB缓存(cache)位于Web服务器和客户端之间. 缓存会根据请求保存输出内容的副本,例如html页面,图片,文件,当下一个请求来到的时候:如果 ...
随机推荐
- git本地分支关联远程分支
问题描述: 从远程master克隆下来以后, 在本地创建wf_dev分支, 此时执行git pull 操作出现图中问题. 这是因为:本地的wf_dev分支还没有和远程的wf_dev进行关联. 执行: ...
- CSP学习之CryptoAPI初识
Crypto API目的就是提供开发者在windows下使用PKI的编程接口. Crypto 提供了很多的加解密相关函数,如编码.解码.加密解密,哈希,数字证书.证书管理证书存储等. 有关 ...
- python的用户输入和while循环
1.函数input()工作原理 函数input()让程序暂停运行,等待用户输入一些文本.获取用户输入后,Python将其存储在一个变量中,以方便你使用. (1)获取数值可以用 int()函数 (2)求 ...
- Android-自定义View实现ImageView播放gif
http://blog.csdn.net/guolin_blog/article/details/11100315 总体思路是这样的 PowerImageView类继承ImageView类 给Powe ...
- 3.storm-starter打包在storm集群上运行
1.使用maven或者其他打包工具将storm-starter打成jar包 2.请将jar包用解压工具打开在根目录下找到defaults.yaml文件并将其删除不然到时会报有multiply defa ...
- php基础--取默认值以及类的继承
(1)对于php的默认值的使用和C++有点类似,都是在函数的输入中填写默认值,以下是php方法中对于默认值的应用: <?phpfunction makecoffee($types = array ...
- Mantis查看问题列表的列名修改_"P","#"两列
在使用mantis的时候,点击菜单上的“查看问题”进去,就会罗列出当前的bug列表,可是列表的标题上存在着“P”和“#”的显示,个人觉得这两列在这里完全没有意义,或者说现有的显示使人觉得疑惑,究竟代表 ...
- CAA介绍(转)
CAA是DS公司正对于其一系列产品,eg:CATIA,ENOVIA,DELIMA,etc,进行二次开发的一个环境.与VC结合的比较紧密.CAAV4是用于Unix/Linux的,到CAAV5才移植到Wi ...
- Selenium2学习(十七)-- js处理日历控件(修改readonly属性)
前言 日历控件是web网站上经常会遇到的一个场景,有些输入框是可以直接输入日期的,有些不能,以我们经常抢票的12306网站为例,详细讲解如何解决日历控件为readonly属性的问题. 基本思路:先用j ...
- HCNA配置手工负载分担模式链路聚合
一.配置手工负载分担模式链路聚合 链路聚合(Link Aggregation)是将—组物理接口捆绑在一起作为一个逻辑接口来增加带宽的一种方法,又称为多接口负载均衡组(Load Sharing Grou ...