Pond 介绍
Pond 是一个 Python 中高效的通用对象池,具有性能好、内存占用小、命中率高的特点。基于近似统计的根据频率自动回收的能力,能够自动调整每个对象池的空闲对象数量。
因为目前 Python 目前没有比较好的、测试用例完备、代码注释完备、文档完善的对象池化库,同时目前的主流对象池库也没有比较智能的自动回收机制。
Pond 可能是 Python 中第一个社区公开的测试用例完整,覆盖率 90% 以上、代码注释完备、文档完善的对象池化库。
Pond 灵感来自于 Apache Commons Pool、Netty Recycler、HikariCP、Caffeine,集合了多家的优点。
其次 Pond 通过使用近似计数的方式以极小的内存空间统计每个对象池的使用频率,并且自动回收。
流量较为随机平均的情况下,默认策略和权重可以降低 48.85% 内存占用,借取命中率 100%。

流量较为符合 2/8 定律的情况下,默认策略和权重可以降低 45.7% 内存占用, 借取命中率 100%。

设计概述
Pond 主要由 FactoryDict、Counter、PooledObjectTree 三部分以及一个单独的回收线程构成。
FactoryDict
使用 Pond 需要实现对象工厂 PooledObjectFactory,PooledObjectFactory 提供对象的创建、初始化、销毁、验证等操作,由 Pond 调用。
所以为了让对象池支持存放完全不同的对象,Pond 使用了一个字典来记录每个工厂类的名称和自己实现的工厂类的实例化对象。
每个 PooledObjectFactory 应该具备创建对象、销毁对象、验证对象是否还可用、重置对象四个功能。
比较特别的是 Pond 支持自动重置对象,因为某些场景下可能会存在对象中要先赋值进行传递,传递完又被回收的情况,为了避免污染建议这种场景下无比实现这个功能。
IT问答库
http://www.mobiletrain.org/qa/
Counter
Counter 中保存了一个近似计数器。
PooledObjectTree
PooleedObjectTree 是个字典,每个 key 对应着一个先进先出的队列,这些队列都是线程安全的。
每个队列中保存着多个 PooleedObject。PooledObejct 保存了创建时间、最后借出的时间以及实际需要的对象。
线程安全
Pond 的借用和回收都是线程安全的。Python 的 queue 模块提供了一个适用于多线程编程的先进先出(FIFO)数据结构。它可以用来安全地在生产者和消费者线程之间传递消息或其他数据。
锁是调用者来处理的,所有多个线程能够安全且容易的使用同样的 Queue 实例工作。而 Pond 的借用和回收都是在操作 queue,所以基本可以认为是线程安全的。
借出机制
在使用 Pond 借出一个对象时,会先检查想要借出的对象的种类是否已经在 PooledObjectTree 存在,如果存在会检查这个对象的对象池是否为空,如果为空会创建一个新的。
如果对象池中有多余的对象,会利用 queue 弹出一个对象并验证这个对象是否可用。如果不可用会自动调用所属的 Factory 清理销毁该对象,同时清理它在 Python 中的 GC 计数,让它更快被 GC 回收,不断拿取下一个直至有可用的。
如果这个对象可用,则会直接返回。当然无论是从对象池中取出对象还是新创建了一个对象,都会利用 Counter 增加一个计数。
回收机制
回收一个对象时会判断目标对象池存不存在,如果存在会检查对象池是否已经满了,满了的话会自动销毁要归还的这个对象。
然后会检查这个对象是否已经被借出太长时间,如果超过了配置的最长时间同样会被清理掉。
自动回收
自动回收时每隔一段时间,默认是 300 s,就会执行一次。自动清理不经常使用的对象池中的对象。