C#中通过LRU实现通用高效的超时连接探测

 更新时间:2018年11月13日 10:56:39   作者:smark  
这篇文章主要介绍了c#中通过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 > 0)
        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(-1, -1);
        lRUDetector.Detection(5000);
        timer.Change(5000, 5000);
      }, null, 5000, 5000);
      System.Threading.ThreadPool.QueueUserWorkItem(o =>
      {
        int i = 0;
        while (true)
        {
          System.Threading.Thread.Sleep(500);
          i++;
          TestDetector testDetector = new TestDetector();
          testDetector.Name = "my name is " + i;
          lRUDetector.Update(testDetector);
        }
      });
      Console.Read();
    }
  }

运行效果:


以上所述是小编给大家介绍的C#中通过LRU实现通用高效的超时连接探测,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

相关文章

  • .Net WInform开发笔记(二)Winform程序运行结构图及TCP协议在Winform中的应用

    .Net WInform开发笔记(二)Winform程序运行结构图及TCP协议在Winform中的应用

    中午没事,把去年刚毕业那会画的几张图翻出来了,大概介绍Winform应用程序运行的过程,以及TCP协议在Winform中的应用。感兴趣的朋友可以了解下;如果有Windows消息机制等基础,很好理解这两张
    2013-01-01
  • C#实现的滚动网页截图功能示例

    C#实现的滚动网页截图功能示例

    这篇文章主要介绍了C#实现的滚动网页截图功能,结合具体实例形式分析了C#图形操作的相关技巧,需要的朋友可以参考下
    2017-07-07
  • c#获取本机的IP地址的代码

    c#获取本机的IP地址的代码

    c#获取本机的IP地址的代码,需要的朋友可以参考一下
    2013-03-03
  • C#对JSON与对象的序列化与反序列化

    C#对JSON与对象的序列化与反序列化

    这篇文章介绍了C#对JSON与对象的序列化与反序列化,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • C#中txt数据写入的几种常见方法

    C#中txt数据写入的几种常见方法

    这篇文章主要给大家介绍了关于C#中txt数据写入的几种常见方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • 深入c#工厂模式的详解

    深入c#工厂模式的详解

    本篇文章是对c#中的工厂模式进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C#/.net程序调用Python的教程分享

    C#/.net程序调用Python的教程分享

    C#的优势在于window下的开发,不仅功能强大而且开发周期短。而python则有众多的第三方库,可以避免自己造轮子,利用C#来做界面,而具体实现使用python来实现可以大大提高开发效率。本文介绍如何使用pythonnet来执行python脚本,希望对大家有所帮助
    2023-03-03
  • C#数字图像处理之图像缩放的方法

    C#数字图像处理之图像缩放的方法

    这篇文章主要介绍了C#数字图像处理之图像缩放的方法,涉及C#针对图像的缩放技巧,需要的朋友可以参考下
    2015-04-04
  • .NET Core开发之配置详解

    .NET Core开发之配置详解

    这篇文章给大家分享了.NET Core开发中相关配置的知识点内容,有需要的朋友们可以参考下。
    2018-08-08
  • C#实现拆分合并Word表格中的单元格

    C#实现拆分合并Word表格中的单元格

    我们在使用Word制作表格时,由于表格较为复杂,只是简单的插入行、列并不能满足我们的需要。要做一个完整的表格,很多时候需要将单元格进行拆分或者合并。本文将详细为您介绍在Word表格中拆分或合并单元格的思路及方法,希望对大家有所帮助
    2022-12-12

最新评论