设计模式之美:Object Pool(对象池)
索引
意图
运用对象池化技术可以显著地提升性能,尤其是当对象的初始化过程代价较大或者频率较高时。
Object pooling can offer a significant performance boost; it is most effective in situations where the cost of initializing a class instance is high, the rate of instantiation of a class is high.
结构
参与者
Reusable
- 类的实例与其他对象进行有限时间的交互。
ReusablePool
- 管理类的实例。
Client
- 使用类的实例。
适用性
当以下情况成立时可以使用 Object Pool 模式:
- 类的实例可重用于交互。
- 类的实例化过程开销较大。
- 类的实例化的频率较高。
- 类参与交互的时间周期有限。
效果
- 节省了创建类的实例的开销。
- 节省了创建类的实例的时间。
- 存储空间随着对象的增多而增大。
相关模式
- 通常,可以使用 Singleton 模式实现 ReusablePool 类。
- Factory Method 模式封装了对象的创建的过程,但其不负责管理对象。Object Pool 负责管理对象。
实现
实现方式(一):实现 DatabaseConnectionPool 类。
如果 Client 调用 ObjectPool 的 AcquireReusable() 方法来获取 Reusable 对象,当在 ObjectPool 中存在可用的 Reusable 对象时,其将一个 Reusable 从池中移除,然后返回该对象。如果池为空,则 ObjectPool 会创建一个新的 Reusable 对象。
- namespace ObjectPoolPattern.Implementation1
- {
- public abstract class ObjectPool<T>
- {
- private TimeSpan _expirationTime;
- private Dictionary<T, DateTime> _unlocked;
- private Dictionary<T, DateTime> _locked;
- private readonly object _sync = new object();
- public ObjectPool()
- {
- _expirationTime = TimeSpan.FromSeconds();
- _locked = new Dictionary<T, DateTime>();
- _unlocked = new Dictionary<T, DateTime>();
- }
- public ObjectPool(TimeSpan expirationTime)
- : this()
- {
- _expirationTime = expirationTime;
- }
- protected abstract T Create();
- public abstract bool Validate(T reusable);
- public abstract void Expire(T reusable);
- public T CheckOut()
- {
- lock (_sync)
- {
- T reusable = default(T);
- if (_unlocked.Count > )
- {
- foreach (var item in _unlocked)
- {
- if ((DateTime.UtcNow - item.Value) > _expirationTime)
- {
- // object has expired
- _unlocked.Remove(item.Key);
- Expire(item.Key);
- }
- else
- {
- if (Validate(item.Key))
- {
- // find a reusable object
- _unlocked.Remove(item.Key);
- _locked.Add(item.Key, DateTime.UtcNow);
- reusable = item.Key;
- break;
- }
- else
- {
- // object failed validation
- _unlocked.Remove(item.Key);
- Expire(item.Key);
- }
- }
- }
- }
- // no object available, create a new one
- if (reusable == null)
- {
- reusable = Create();
- _locked.Add(reusable, DateTime.UtcNow);
- }
- return reusable;
- }
- }
- public void CheckIn(T reusable)
- {
- lock (_sync)
- {
- _locked.Remove(reusable);
- _unlocked.Add(reusable, DateTime.UtcNow);
- }
- }
- }
- public class DatabaseConnection : IDisposable
- {
- // do some heavy works
- public DatabaseConnection(string connectionString)
- {
- }
- public bool IsOpen { get; set; }
- // release something
- public void Dispose()
- {
- }
- }
- public class DatabaseConnectionPool : ObjectPool<DatabaseConnection>
- {
- private string _connectionString;
- public DatabaseConnectionPool(string connectionString)
- : base(TimeSpan.FromMinutes())
- {
- this._connectionString = connectionString;
- }
- protected override DatabaseConnection Create()
- {
- return new DatabaseConnection(_connectionString);
- }
- public override void Expire(DatabaseConnection connection)
- {
- connection.Dispose();
- }
- public override bool Validate(DatabaseConnection connection)
- {
- return connection.IsOpen;
- }
- }
- public class Client
- {
- public static void TestCase1()
- {
- // Create the ConnectionPool:
- DatabaseConnectionPool pool = new DatabaseConnectionPool(
- "Data Source=DENNIS;Initial Catalog=TESTDB;Integrated Security=True;");
- // Get a connection:
- DatabaseConnection connection = pool.CheckOut();
- // Use the connection
- // Return the connection:
- pool.CheckIn(connection);
- }
- }
- }
实现方式(二):使用对象构造方法和预分配方式实现 ObjectPool 类。
- namespace ObjectPoolPattern.Implementation2
- {
- /// <summary>
- /// 对象池
- /// </summary>
- /// <typeparam name="T">对象类型</typeparam>
- public class ObjectPool<T> where T : class
- {
- private readonly Func<T> _objectFactory;
- private readonly ConcurrentQueue<T> _queue = new ConcurrentQueue<T>();
- /// <summary>
- /// 对象池
- /// </summary>
- /// <param name="objectFactory">构造缓存对象的函数</param>
- public ObjectPool(Func<T> objectFactory)
- {
- _objectFactory = objectFactory;
- }
- /// <summary>
- /// 构造指定数量的对象
- /// </summary>
- /// <param name="count">数量</param>
- public void Allocate(int count)
- {
- for (int i = ; i < count; i++)
- _queue.Enqueue(_objectFactory());
- }
- /// <summary>
- /// 缓存一个对象
- /// </summary>
- /// <param name="obj">对象</param>
- public void Enqueue(T obj)
- {
- _queue.Enqueue(obj);
- }
- /// <summary>
- /// 获取一个对象
- /// </summary>
- /// <returns>对象</returns>
- public T Dequeue()
- {
- T obj;
- return !_queue.TryDequeue(out obj) ? _objectFactory() : obj;
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- var pool = new ObjectPool<byte[]>(() => new byte[]);
- pool.Allocate();
- var buffer = pool.Dequeue();
- // .. do something here ..
- pool.Enqueue(buffer);
- }
- }
- }
《设计模式之美》为 Dennis Gao 发布于博客园的系列文章,任何未经作者本人同意的人为或爬虫转载均为耍流氓。
设计模式之美:Object Pool(对象池)的更多相关文章
- Object Pool 对象池的C++11使用(转)
很多系统对资源的访问快捷性及可预测性有严格要求,列入包括网络连接.对象实例.线程和内存.而且还要求解决方案可扩展,能应付存在大量资源的情形. object pool针对特定类型的对象循环利用,这些对象 ...
- JedisCluster中应用的Apache Commons Pool对象池技术
对象池技术在服务器开发上应用广泛.在各种对象池的实现中,尤其以数据库的连接池最为明显,可以说是每个服务器必须实现的部分. apache common pool 官方文档可以参考:https://c ...
- Object Pooling(对象池)实现
在文章开始之前首先要思考的问题是为什么要建立对象池.这和.NET垃圾回收机制有关,正如下面引用所说,内存不是无限的,垃圾回收器最终要回收对象,释放内存.尽管.NET为垃圾回收已经进行了大量优化,例如将 ...
- .NET Core中Object Pool的简单使用
前言 复用,是一个重要的话题,也是我们日常开发中经常遇到的,不可避免的问题. 举个最为简单,大家最为熟悉的例子,数据库连接池,就是复用数据库连接. 那么复用的意义在那里呢? 简单来说就是减少不必要的资 ...
- java对象池化技术
https://blog.csdn.net/tiane5hao/article/details/85957840 文章目录 先写一个简单通用的对象池 通过上面的通用池实现jedis连接池 连接池测试 ...
- 缓冲&缓存&对象池概念的理解
一).缓冲 作用:缓解程序上下层之间的性能差异. 1).当上层组件的性能优于下层组件时加入缓冲机制可以减少上层组件对下 层组件的等待时间. 2).上层组件不需要等待下层组件接收全部数据,即可返回操作, ...
- Java堆外内存之一:堆外内存场景介绍(对象池VS堆外内存)
最近经常有人问我在Java中使用堆外(off heap)内存的好处与用途何在.我想其他面临几样选择的人应该也会对这个答案感兴趣吧. 堆外内存其实并无特别之处.线程栈,应用程序代码,NIO缓存用的都是堆 ...
- Unity实现简单的对象池
一.简介 先说说为什么要使用对象池 在Unity游戏运行时,经常需要生成一些物体,例如子弹.敌人等.虽然Unity中有Instantiate()方法可以使用,但是在某些情况下并不高效.特别是对于那些需 ...
- [译]Unity3D内存管理——对象池(Object Pool)
原文地址:C# Memory Management for Unity Developers (part 3 of 3), 其实从原文标题可以看出,这是一系列文章中的第三篇,前两篇讲解了从C#语言本身 ...
随机推荐
- SQLMAP 中$与#的区别
在sql配置中比如in(#rewr#) 与in ($rewr$) 在Ibatis中我们使用SqlMap进行Sql查询时需要引用参数,在参数引用中遇到的符号#和$之间的区分为,#可以进行与编译,进行类型 ...
- html理解
dispay:inline-block: display:inline不会独占一行,会排在同一行里 display:block 独占一行多个block会各自重起一行 margin:容器外间距 容器到 ...
- My97Datepicker 去掉 “不合法格式或超期范围”自动纠错限制
官网上,纠错有以下三种,如日期格式不对,或超期,则必须纠错过后,才能继续操作, 但有时,可能允许出错,需要把纠错功能去掉,则可以设置errDealMode = 3,这种模式是官网说没有的, 但能够去掉 ...
- html input的file文件输入框onchange事件触发一次失效解决方法
最近在做一个图片上传的功能,出现提交一次后,file输入框的change事件无法再次触发的bug,就是说提交一次后必须刷新才能再次提交,这就坑了~ 于是想办法解决它~ 在网上找了一些资料,找到这几种方 ...
- android/ios js 启动apk
1.在移动设备访问某个连接时时,如果本地安装了其应用客户端,则浏览器会调用本地客户端,没有安装则会跳转到下载页面,提示安装.刚好有这样的需求,网上参考了其他人的实现,大部分都是关于APK和本地js交互 ...
- JavaScript-取消事件-e.preventDefault();
取消事件:(阻止默认行为) 当事件执行过程中,遇到问题,可取消事件.不再触发 如何e.preventDefault(); <!DOCTYPE html> <html> < ...
- flask_单元测试
我们现在可以试着在控制台向数据库添加一个用户: In[2]: import model; In[3]: from microblog import db; In[4]: u=model.User(ni ...
- webkit浏览器css设置滚动条
主要有下面7个属性: ::-webkit-scrollbar 滚动条整体部分,可以设置宽度啥的 ::-webkit-scrollbar-button 滚动条两端的按钮 ::-webkit-scroll ...
- iOS-三方框架AFNetworking基本使用
AFNetworking 是基于NSURLConnection, NSOperation开发的一款三方框架,主要用于处理一些关于网络请求上的业务,下文会简单介绍框架中经常使用的功能,如文件的上传,下载 ...
- 8.4.3 Glide
1). 导入库 dependencies { compile 'com.github.bumptech.glide:glide:3.5.2' compile 'com.android.support: ...