设计一个对象池(Anno.XObjectPool)
设计一个.net对象池
对象池对于创建开销比较大的对象来说很有意义,为了优化程序的运行速度、避免频繁创建销毁开销比较大的对象,我们可以通过对象池来复用创建开销大的对象。对象池的思路比较简单,事先创建好一批对象,放到一个集合中,以后每当程序需要新的对象时候,都从对象池里获取,每当程序用完该对象后,都把该对象归还给对象池。这样会避免重复的对象创建,提高程序性能。
应用场景
在Anno微服务框架中的使用,由于客户端调用微服的时候需要建立Socket连接,频繁的创建和销毁连接会有很大的开销。所以我们设想我们如果可以重复利用这些对象那么性能上也会是很大的提升。这时候我们就需要一个对象池来存放这些可以重复利用的对象。不仅如此我们还需要可以控制对象池的最大存活对象数量、最小闲置对象数量、最大闲置对象数量、如何创建对象、销毁对象、定期清理闲置对象。(网上没找到好用的于是开始造我们的轮子)
Install-Package Anno.XObjectPool -Version 1.0.3.4
Xpool核心代码

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace Anno.XObjectPool
{
public class XPool<T> : IDisposable
{
private bool disposed;
private XPoolConfiguration xcfg;
/// <summary>
/// 初始化对象池
/// </summary>
/// <param name="createObject">创建XObject对象</param>
/// <param name="activeXObject"> 获取XObject对象之前验证True 有效</param>
public XPool(Func<T> createObject, Func<T, bool> activeXObject = null) : this(new XPoolConfiguration()
{
MaxActive = 1000,
MaxIdle = 400,
MinIdle = 10
}, createObject, activeXObject)
{ }
/// <summary>
/// 初始化对象池
/// </summary>
/// <param name="maxActive">最大活动数量</param>
/// <param name="minIdle">最小空闲数量</param>
/// <param name="maxIdle">最大空闲数量</param>
/// <param name="createObject">创建XObject对象</param>
/// <param name="activeXObject"> 获取XObject对象之前验证True 有效</param>
public XPool(int maxActive, int minIdle, int maxIdle, Func<T> createObject, Func<T, bool> activeXObject = null)
{
xcfg = new XPoolConfiguration()
{
MaxActive = maxActive,
MaxIdle = maxIdle,
MinIdle = minIdle
};
pools = new ConcurrentStack<XObject<T>>();
ResetEvent = new AutoResetEvent(false);
if (createObject != null)
{
CreateXObject = createObject;
}
else
{
throw new ArgumentNullException("createObject 不能为空");
}
if (activeXObject != null)
{
ActiveXObject = activeXObject;
}
Parallel.For(0, minIdle, x =>
{
pools.Push(new XObject<T>()
{
Value = CreateXObject.Invoke(),
LastDateTime = DateTime.Now,
Pool = this
});
});
StartTaskClearLongIdleXObject();
}
/// <summary>
/// 初始化对象池
/// </summary>
/// <param name="xcfg">对象池配置</param>
/// <param name="createObject">创建XObject对象</param>
/// <param name="activeXObject"> 获取XObject对象之前验证True 有效</param>
public XPool(XPoolConfiguration xcfg, Func<T> createObject, Func<T, bool> activeXObject = null) : this(xcfg.MaxActive, xcfg.MinIdle, xcfg.MaxIdle, createObject, activeXObject)
{ }
private ConcurrentStack<XObject<T>> pools;
private int _activedTransportCount = 0;
private AutoResetEvent ResetEvent { get; set; }
/// <summary>
/// 活动链接数量
/// </summary>
public int ActivedTransportCount => _activedTransportCount; /// <summary>
/// 原子性增加 活动链接数量
/// </summary>
private void InterlockedIncrement()
{
Interlocked.Increment(ref _activedTransportCount);
}
/// <summary>
/// 原子性减少 活动链接数量
/// </summary>
private void InterlockedDecrement()
{
Interlocked.Decrement(ref _activedTransportCount);
} public XObject<T> Borrow(TimeSpan? timeout = null)
{
if (!pools.TryPop(out XObject<T> xobj))
{
if (pools.Count < xcfg.MinIdle && _activedTransportCount < xcfg.MaxActive)
{
pools.Push(new XObject<T>()
{
Value = CreateXObject.Invoke(),
LastDateTime = DateTime.Now,
Pool = this
});
}
if (!pools.Any() && _activedTransportCount >= xcfg.MaxActive)
{
int millisecondsTimeout = 20000;
if (timeout.HasValue && timeout.Value.TotalMilliseconds > 0)
{
millisecondsTimeout = (int)timeout.Value.TotalMilliseconds;
}
bool result = ResetEvent.WaitOne(millisecondsTimeout);
if (!result)
{
throw new TimeoutException($"Timeout对象池等待超时!");
}
}
if (!pools.TryPop(out xobj))
{
xobj = new XObject<T>()
{
Value = CreateXObject.Invoke(),
LastDateTime = DateTime.Now,
Pool = this
};
}
}
InterlockedIncrement();
//借出之前判断对象是否有效
if (!ActiveXObject(xobj.Value))
{
throw new InvalidOperationException("对象无效,请在有效性检测函数activeXObject中设置有效性");
}
return xobj;
}
public void Return(XObject<T> xObject, bool isDispose = false)
{
if (xObject == null)
{
throw new ArgumentNullException("xObject 不能为空!");
}
/*
* 主动释放的释放
* 超出最大闲置数量的释放
* 无效的释放
*/
if (isDispose || _activedTransportCount > xcfg.MaxIdle || !ActiveXObject(xObject.Value))
{
DisposeXObject(xObject);
xObject.Pool = null;
InterlockedDecrement();
return;
}
xObject.LastDateTime = DateTime.Now;
pools.Push(xObject);
InterlockedDecrement();
ResetEvent.Set();
} private void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
try
{
while (pools.TryPop(out XObject<T> xobj))
{
//Pool 释放的时候XObject不再归还到Pool
DisposeXObject(xobj);
xobj.Pool = null;
}
}
catch (Exception)
{ }
}
disposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
} /// <summary>
/// 创建XObject对象
/// </summary>
public Func<T> CreateXObject { get; set; } = () => { return default(T); };
/// <summary>
/// 获取XObject对象之前验证True 有效
/// </summary>
public Func<T, bool> ActiveXObject { get; set; } = x => { return true; };
/// <summary>
/// 释放XObject时候触发
/// </summary>
public Action<XObject<T>> DisposeXObject { get; set; } = x => { };
/// <summary>
/// 移除长度为count的元素
/// </summary>
/// <param name="count">除元素的长度count</param>
private void DisposeLongIdleXObject(int count)
{
int startIndex = pools.Count - count;
XObject<T>[] popXObjects = new XObject<T>[count];
pools.TryPopRange(popXObjects, 0, count);
for (int i = 0; i < popXObjects.Length; i++)
{
Return(popXObjects[i], true);
}
}
/// <summary>
/// 每隔10秒检测一次清理30秒未使用的对象数量的对象
/// (如果存在对象30未使用,说明对象池有对象长时间闲置未使用)则从头部弹出一定数量的对象释放掉
/// </summary>
private void StartTaskClearLongIdleXObject()
{
Task.Factory.StartNew(async () =>
{
while (!disposed)
{
await Task.Delay(10000);
try
{
var removeCount = 0;
var now = DateTime.Now.AddSeconds(-30);
var _pools = pools.ToList();
for (int i = _pools.Count - 1; i >= xcfg.MinIdle; i--)
{
if (_pools[i].LastDateTime < now)
{
removeCount++;
}
}
if (removeCount > 0 && removeCount <= (pools.Count - xcfg.MinIdle))
{
DisposeLongIdleXObject(removeCount);
}
}
finally { }
}
}, TaskCreationOptions.LongRunning);
}
}
}
初始化一个对象池
最大活动对象数量 50个,最小闲置对象数量2个,最大闲置数量20个。
var UserPool = new XPool<User>(50, 2, 20, () =>
{
int age = Interlocked.Increment(ref _activedTransportCount);
return new User()
{
Age = age,
Name = $"Name{age}" };
});
并行调用
200个并行调用
Parallel.For(0, 200, x =>
{
using (var user = UserPool.Borrow())
{
Console.WriteLine($"Age:{user.Value.Age},Name:{user.Value.Name}");//,Msg:{user.Value.Msg}
}
});
结果:

从上图我们看到在200个并行过程中,只有4个对象被使用。因此可以看出我们没有频繁的创建对象。
欢迎加入QQ群:478399354 ,到这里我们互为师长项目学习。

Anno开源地址:
AnnoGitHub源码:https://github.com/duyanming/Anno.Core
AnnoGitee源码:https://gitee.com/dotnetchina/anno.core
Viper示例项目:https://github.com/duyanming/Viper
体验地址:http://140.143.207.244/Home/Login
文档地址:https://duyanming.github.io/
关于Anno的更多内容,随后更新。敬请关注。开源不易,感谢Star。
设计一个对象池(Anno.XObjectPool)的更多相关文章
- swift实现一个对象池
1.创建一个对象池 对象池:对象池一般用来管理一组可重用的对象, 这些对象的集合叫做对象池. 组件可以从对象池中借用对象, 完成一些任务之后将它归还给对象池. 返回的对象用于满足调用组件的后续请求, ...
- 前端通信:ajax设计方案(八)--- 设计请求池,复用请求,让前端通信快、更快、再快一点
直接进入主题,本篇文章有点长,包括从设计阶段,到摸索阶段,再到实现阶段,最后全面覆盖测试阶段(包括数据搜集清洗),还有与主流前端通信框架进行对比PK阶段. 首先介绍一下一些概念: 1. 浏览器的并发能 ...
- php 设计数据库连接池
摘要 之前总是以脚本面向过程的方式写PHP代码,所以很大程度上来说,既不规范,也不安全,更不容易维护.为了代码的重用,准备写一套自己的工具库,这样的话,以后写项目的时候就可以很轻松的进行使用啦. 今天 ...
- java设计思想-池化-手写数据库连接池
https://blog.csdn.net/qq_16038125/article/details/80180941 池:同一类对象集合 连接池的作用 1. 资源重用 由于数据库连接得到重用,避免了 ...
- java对象池commons-pool-1.6详解(一)
自己的项目中用到了 对象池 commons-pool: package com.sankuai.qcs.regulation.protocol.client; import com.dianping. ...
- netty源码分析 - Recycler 对象池的设计
目录 一.为什么需要对象池 二.使用姿势 2.1 同线程创建回收对象 2.2 异线程创建回收对象 三.数据结构 3.1 物理数据结构图 3.2 逻辑数据结构图(重要) 四.源码分析 4.2.同线程获取 ...
- 抓到 Netty 一个隐藏很深的内存泄露 Bug | 详解 Recycler 对象池的精妙设计与实现
欢迎关注公众号:bin的技术小屋,如果大家在看文章的时候发现图片加载不了,可以到公众号查看原文 本系列Netty源码解析文章基于 4.1.56.Final版本 最近在 Review Netty 代码的 ...
- Linux编程之内存池的设计与实现(C++98)
假设服务器的硬件资源"充裕",那么提高服务器性能的一个很直接的方法就是空间换时间,即"浪费"服务器的硬件资源,以换取其运行效率.提升服务器性能的一个重要方法就是 ...
- Spring线程池配置模板设计(基于Springboot)
目录 线程池配置模板 基础的注解解释 常用配置参数 配置类设计 线程池使用 ThreadPoolTaskExecutor源码 线程池配置模板 springboot给我们提供了一个线程池的实现,它的底层 ...
随机推荐
- 如何学习python爬虫
分享网易云课堂上一个不错的视频教学:http://study.163.com/course/courseMain.htm?courseId=1003285002
- JS逆向-抠代码的第四天【手把手学会抠代码】
今天是md5巩固项目,该项目比昨天的复杂一些,但方法思路是一样的. 今天的目标:https://www.webportal.top/ 打开网站,填入账号密码(密码项目以123456做测试).点击登录抓 ...
- IPFS矿机封装原理解释
近期无论是从媒体.新闻的高度曝光,还是市场拓展的覆盖度来看,IPFS 俨然成为今年最值得关注的行业话题与入场趋势.对于许多刚了解 IPFS 的小白来说,矿机的「封装」.「有效算力」和「原值算力」这些概 ...
- sqli-labs系列——第二关
less2 and 1=1有回显,and 1=2无回显,为数值型注入 order by 4–+报错,有3行 查询数据库名 ?id=0' union select 1,(select group_con ...
- 「HTML+CSS」--自定义加载动画【008】
前言 Hello!小伙伴! 首先非常感谢您阅读海轰的文章,倘若文中有错误的地方,欢迎您指出- 哈哈 自我介绍一下 昵称:海轰 标签:程序猿一只|C++选手|学生 简介:因C语言结识编程,随后转入计算机 ...
- 打造云原生大型分布式监控系统系列文章-腾讯工程师roc
附上本系列文章链接 打造云原生大型分布式监控系统(一): 大规模场景下 Prometheus 的优化手段 打造云原生大型分布式监控系统(二): Thanos 架构详解 打造云原生大型分布式监控系统(二 ...
- ECharts使用指南
第一步,引入ECharts: echars的引入十分简单,只需要在html中嵌入即可: <!DOCTYPE html> <html> <head> <scri ...
- 问题笔记 - element表格 操作状态值
1.必须从传到表里的数据源中取值(scope.row.star)
- OO UNIT 1 个人单元总结
面向对象课程--第一单元个人总结 作业分析 第一次作业 概要 本次作业主要对简单幂函数的多项式进行求导计算,要点在于对输入字符串的处理,利用正则表达式匹配即可,并且需要对输出表达式的长度进行优化. 度 ...
- .netcore ioc 循环依赖问题及其相关思考之DispatchProxy
.netcore引入了ioc机制让开发人员逐步习惯从过去的各种new对象变成通过IOC框架来管理对象的生命周期.这样当我们需要某个对象的时候,我们一般在构造函数里申明该对象的接口,即可通过ioc容器创 ...