通过LRU实现通用高效的超时连接探测
编写网络通讯都要面对一个问题,就是要把很久不存活的死连接清除,如果不这样做那死连接最终会占用大量内存影响服务运作!在实现过程中一般都会使用ping,pong原理,通过ping,pong来更新连接的时效性,最后通过扫描连接列表来清除掉。虽然这种做法比较简单,但很难抽取出通用性的封装,扫描整个列表复杂度也比较高。以下讲解如何通过LRU算法实现一个通用高效的探测超时连接功能类。
什么是LRU
在这里还是要大概介绍一下LRU,LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小.也就是说,当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰.当然在这里并不需要使用到自动淘汰机制,只需要把未位到达超时的连接清除即可。
在C#中如何实现LRU
C#并不存在这样的数据结构,不过有一个结构很适合实现LRU,这个结构就是LinkedList
双向链表,通过以下结构图就容易理解通过LinkedList
实现LRU
通过LinkedList
的功能我们可以把活越项先移出来,然后再把项移到头部。在这里需要注意LinkedList
的Remove
方法,它有两个重载版本,两个版本的复杂度不一样。一个是O(n)一个是O(1)所以使用上一定要注意,否则在数据多的情况下效率差别巨大(这些细节都可以通过源代码来查看)!
代码实现
前面已经大概讲述的原理,接下来要做的就是代码实现了。第一步需要制订一个基础可控测对象规则接口,这样就可以让现有的已经实现的功能实现它并可得到相关功能的支持。
public interface IDetector
{
double ActiveTime
{ get; set; }
LinkedListNode<IDetector> DetectorNode
{
get;
set;
}
}
接口定义了两个属性,一个是最近活越时间,另一个就是LinkedListNode<IDetector>
这个属性比交关键,通过LinkedListNode<IDetector>
可以让LinkedList
在Remove
时复杂度为O(1).接下来就要针对基于LRU算法处理超时制定一个应用规则
public interface ILRUDetector
{
void Update(IDetector item); void Detection(int timeout); double GetTime(); Action<IList<IDetector>> Timeout { get; set; }
}
规则也是比较简单,Update
用于更新跟踪对象,一般在处理接受ping或pong包后进行调用;Detection
方法是探测超出指定时间的对象,时间当位是毫秒,如果存在有超时的对象则触发Timeout
事件;GetTime
是获取探测器已经运行的时间单位毫秒!规则定好了那接着要做的事实就是要实现它:
class LRUDetector : ILRUDetector, IDisposable
{
public LRUDetector()
{
mTimeWatch = new System.Diagnostics.Stopwatch();
mTimeWatch.Restart();
}
private Buffers.XSpinLock xSpinLock = new Buffers.XSpinLock();
private System.Diagnostics.Stopwatch mTimeWatch;
private LinkedList<IDetector> mItems = new LinkedList<IDetector>();
public Action<IList<IDetector>> Timeout
{
get; set;
}
public void Detection(int timeout)
{
double time = GetTime();
List<IDetector> result = new List<IDetector>();
using (xSpinLock.Enter())
{
LinkedListNode<IDetector> last = mItems.Last;
while (last != null && (time - last.Value.ActiveTime) > timeout)
{
mItems.Remove(last);
result.Add(last.Value);
last.Value.DetectorNode = null;
last = mItems.Last;
}
}
if (Timeout != null && result.Count > )
Timeout(result);
}
public void Update(IDetector item)
{
using (xSpinLock.Enter())
{
if (item.DetectorNode == null)
item.DetectorNode = new LinkedListNode<IDetector>(item);
item.ActiveTime = GetTime();
if (item.DetectorNode.List == mItems)
mItems.Remove(item.DetectorNode);
mItems.AddFirst(item);
}
}
public void Dispose()
{
mItems.Clear();
}
public double GetTime()
{
return mTimeWatch.Elapsed.TotalMilliseconds;
}
}
代码并不复杂,相信不用过多解释也能看懂相关操作原理。
测试
既然功能已经实现,接下来就要对代码进行测试看运行效果。测试代码比较简单首先开启一个Timer
定时执行Detection
,另外开一个线程去调用Update
方法
class Program
{
public class TestDetector : IDetector
{
public double ActiveTime { get; set; }
public string Name { get; set; }
public LinkedListNode<IDetector> DetectorNode { get; set; }
}
static void Main(string[] args)
{
LRUDetector lRUDetector = new LRUDetector();
lRUDetector.Timeout = (items) =>
{
foreach (TestDetector item in items)
Console.WriteLine($"{(item.Name)} timeout {lRUDetector.GetTime() - item.ActiveTime}ms");
};
System.Threading.Timer timer = null;
timer = new System.Threading.Timer(o =>
{
timer.Change(-, -);
lRUDetector.Detection();
timer.Change(, );
}, null, , );
System.Threading.ThreadPool.QueueUserWorkItem(o =>
{
int i = ;
while (true)
{
System.Threading.Thread.Sleep();
i++;
TestDetector testDetector = new TestDetector();
testDetector.Name = "my name is " + i;
lRUDetector.Update(testDetector);
}
});
Console.Read();
}
}
运行效果:
通过LRU实现通用高效的超时连接探测的更多相关文章
- linux上搭建ftp、vsftp, 解决访问ftp超时连接, 解决用户指定访问其根目录,解决ftp主动连接、被动连接的问题
linux上搭建ftp 重要 解决如何搭建ftp 解决用户指定访问其根目录 解决访问ftp超时连接 解决ftp主动连接.被动连接的问题 1.安装ftp ...
- TCP连接探测中的Keepalive和心跳包
TCP连接探测中的Keepalive和心跳包 tcp keepalive 心跳 保活 Linuxtcp心跳keepalive保活1. TCP保活的必要性 1) 很多防火墙等对于空闲socket自动关闭 ...
- 10w定时任务,如何高效触发超时
一.缘起 很多时候,业务有定时任务或者定时超时的需求,当任务量很大时,可能需要维护大量的timer,或者进行低效的扫描. 例如:58到家APP实时消息通道系统,对每个用户会维护一个APP到服务器的TC ...
- MYSQL超时连接问题(com.mysql.jdbc.MysqlIO.readFully)
应用服务器连接mysql,有时候会出现以下异常: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.jav ...
- 高效管理http连接
1.Http连接基础 Http协议承载了互联网上的主要流量,然而说到传输,还要回归到最基本的网络分层模型TCP/IP.TCP/IP是全球计算机及网络设备都在使用的一种常用的分组交互网络分层协议集.客户 ...
- linux下的epoll怎样高效处理百万连接
开发高性能网络程序时.windows开发人员们言必称iocp,linux开发人员们则言必称epoll.大家都明确epoll是一种IO多路复用技术,能够很高效的处理数以百万计的socket句柄,比起曾经 ...
- 通用高效的数据修复方法:Row level repair
导读:随着大数据的进一步发展,NoSQL 数据库系统迅速发展并得到了广泛的应用.其中,Apache Cassandra 是最广泛使用的数据库之一.对于 Cassandra 的优化是大家研究的热点,而 ...
- 抓到 Netty 一个 Bug,顺带来透彻地聊一下 Netty 是如何高效接收网络连接的
本系列Netty源码解析文章基于 4.1.56.Final版本 对于一个高性能网络通讯框架来说,最最重要也是最核心的工作就是如何高效的接收客户端连接,这就好比我们开了一个饭店,那么迎接客人就是饭店最重 ...
- svn 连接超时,连接失败解决办法
1.确认服务是否开启 2.Windows防火墙是否开启,如开启则关闭防火墙 3.安全软件是否将3306与443端口关闭. 关闭后无法连接
随机推荐
- quartz之CronExpression表达式
一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素.按顺序依次为1.秒(~).分钟(~).小时(~).天(月)(~,但是你需要考虑你月的天数).月(~).天(星期)(~ =SUN 或 SU ...
- windows与linux多线程对比
一.创建线程 1>windows HANDLE aThread[MAX_THREAD]; 函数原型: HANDLE WINAPI CreateThread( _In_opt_ LPSECUR ...
- ODM、JDM、OEM概念
OEM (Original Equipment Manufacturer) - 原始设备制造商 委托生产,或者说“代工生产”,其含义是品牌厂商不直接制造产品,而是负责设计和开发新产品,控制销售“渠道” ...
- RSP小组——团队冲刺博客二
RSP小组--团队冲刺博客二 冲刺日期:2018年12月11日 前言 经过第一天的冲刺,我们开始了我们冲刺之路,但是不知为什么,我们的动力并不足,首先可能是我们前期对该项目的编制过程中,因为没有经验, ...
- Tomcat6,7,8的日志切割
使用的日志切割工具cronolog(yum就可以了) 确定好路径后,开始配置 Tomcat6 Tomcat6/bin/catalina.sh 292-317行(修改两处) 修改之后为下面的内容 # t ...
- java代码编译与C/C++代码编译的区别
Java编译原理 1.Java编译过程与c/c++编译过程不同 Java编译程序将java源程序编译成jvm可执行代码--java字节码. Java在编译过程中一般会按照以下过程进行: (1)JDK根 ...
- Apache Maven入门篇(转)
[上篇] 写这个 maven 的入门篇是因为之前在一个开发者会的动手实验中发现挺多人对于 maven 不是那么了解,所以就有了这个想法.这个入门篇分上下两篇.本文着重动手,用 maven 来构建运行 ...
- django+javascrpt+python实现私有云盘代码
丁丁:由于篇幅有限,这里暂时只展示python后端代码,前端js代码后面上传,有需要的也可以留言私信我. 1.view.py 使用用户.部门.公司等相关账号的创建,已经个人,部门账号的冻结,删除,相关 ...
- 34 文件地理数据库(GDB)变文件夹了怎么办
我们都知道文件地理数据库(GDB)是ArcGIS软件特有的格式,有其独特的设计之处,在文件资源管理器中显示为.gdb的文件夹,但是里面的文件却看不明白,而且将gdb文件夹在Windows资源管理器中直 ...
- framework7 入门(基础布局)
个人认为framework7是个很好的移动端框架,自带路由.下拉刷新.无限加载.时间线.各种dialog.环形图等,基本能满足大部分app的需求,可以和vue,webpack 等各种搭配. 这里讲一下 ...