第二十七章 对象池技术
1. 核心思想
对象池是一个集合,里面包含了我们需要的已经过初始化且可以使用的对象。我们称这些对象都被池化了,也就是被对象池所管理,想要使用这样的对象,从池子里取一个就行,但是用完得归还。可以将对象池理解为单例模式的延展一多例模式。对象实例是有限的,要用可以,但用完必须归还,这样其他人才能再使用。
2. UML类图
3. 框架代码
from abc import ABC,abstractmethod
from time import strftime, localtime, time
class PooledObject:
"""池对象,也称池化对象,对象池中的对象
"""
def __init__(self, obj=None) -> None:
self.__obj = obj
self.__busy = False
def getObject(self):
return self.__obj
def setObject(self, obj):
self.__obj = obj
def isBusy(self):
return self.__busy
def setBusy(self, busy):
self.__busy = busy
class ObjectPool(ABC):
"""对象池
Args:
ABC (metaClass): 抽象类
"""
initialNumberOfObject = 2 # 对象池初始化大小
maxNUmberOfObject = 3 # 对象池最大的大小
def __init__(self) -> None:
self.__pool:list[PooledObject] = []
for _ in range(ObjectPool.initialNumberOfObject):
self.__pool.append(self.createPooledObject())
@abstractmethod
def createPooledObject(self):
pass
def borrowObject(self):
pooledObject:PooledObject = self._findFreePooledObject()
if pooledObject is not None:
pooledObject.setBusy(True)
print("{}对象已被借用,time:{}".format(id(pooledObject.getObject()), strftime("%Y-%m-%d %H:%M:%s", localtime(time()))))
else:
pooledObject = self.addObject()
if pooledObject is None:
print("对象池中没有空余对象,借出失败!!!")
print(f"对象池中有:{len(self.__pool)},已借:{len(list(filter(lambda x:x.isBusy(),self.__pool)))},还剩:{len(list(filter(lambda x:not x.isBusy(),self.__pool)))}")
return pooledObject.getObject() if pooledObject is not None else None
def returnObject(self, obj):
for pooledObject in self.__pool:
if pooledObject.getObject() == obj:
pooledObject.setBusy(False)
print("{}对象已归返,time:{}".format(id(obj), strftime("%Y-%m-%d %H:%M:%s", localtime(time()))))
return True
def addObject(self):
obj = None
if len(self.__pool)<ObjectPool.maxNUmberOfObject:
obj = self.createPooledObject()
self.__pool.append(obj)
print("添加新对象{},time:{}".format(id(obj), strftime("%Y-%m-%d %H:%M:%s", localtime(time()))))
return obj
def clear(self):
self.__pool.clear()
def _findFreePooledObject(self):
pooledObj = None
for obj in self.__pool:
if not obj.isBusy():
pooledObj = obj
break
return pooledObj
class PowerBank:
def __init__(self, serialNUmber, electricQuantity) -> None:
self.__serialNumber = serialNUmber
self.__electricQuantity = electricQuantity
self.__user = "NA"
def getSerialNumber(self):
return self.__serialNumber
def getElectricQuantity(self):
return self.__electricQuantity
def setElectricQuantity(self, electricQuantity):
self.__electricQuantity = electricQuantity
def setUser(self, user):
self.__user = user
def getUser(self):
return self.__user
def __str__(self) -> str:
return "序列号:{}\t电量:{:.2%}\t使用者:{}".format(self.__serialNumber, self.__electricQuantity,self.__user)
class PowerBankPool(ObjectPool):
__serialNumber = 0
@classmethod
def getSerilNUmber(cls):
cls.__serialNumber += 1
return "{:03d}".format(cls.__serialNumber)
def createPooledObject(self):
powerBank = PowerBank(PowerBankPool.getSerilNUmber(), 1)
return PooledObject(powerBank)
if __name__ == "__main__":
pbp = PowerBankPool()
pb_1:PowerBank = pbp.borrowObject()
if pb_1 is not None:
pb_1.setUser("Nie")
print(pb_1)
pb_2:PowerBank = pbp.borrowObject()
if pb_2 is not None:
pb_2.setUser("Wen")
print(pb_2)
pb_3 = pbp.borrowObject()
if pb_3 is not None:
pb_3.setUser("Qing")
print(pb_3)
pb_4 = pbp.borrowObject()
if pb_4 is not None:
pb_4.setUser("Wen")
print(pb_4)
if pbp.returnObject(pb_2):
pb_2.setUser("NA")
pb_2.setElectricQuantity(0.74)
print(pb_2)
pb = pbp.borrowObject()
if pb is not None:
pb.setUser("Wen")
print(pb)
pb = pbp.borrowObject()
if pb is not None:
pb.setUser("Wen")
print(pb)
4. 模型说明
4.1 设计要点
对象池机制有两个核心对象和三个关键动作对象(Object)
- 两个核心对象
- 要进行池化的对象:通常是一些创建和销毁时会非常耗时,或对象本身非常占内存的对象。
- 对象池(Object Pool):对象的集合,其实就是对象的管理器,管理对象的借用、归还。
- 三个关键动作对象
- 借用对象(borrow object):从对象池中获取对象。
- 使用对象(using object):即使用对象进行业务逻辑的处理。
- 归还对象(return、 give back):将对象归还对象池,归还后这个对象的引用不能再用于其他对象,除
非重新获取对象。
4.2 优缺点
- 优点
- 对象池机制通过借用、归还的思想,实现了对象的重复利用,能有效地节约内存,提升程序性能。
- 缺点
- 借用和归还必须成对出现,用完必须归还,不然这个对象将一直处于被占用状态。
- 对已归还的对象的引用,不能再进行任何其他的操作,否则将产生不可预料的结果。
5. 应用场景
对象池机制特别适用于那些初始化和销段的代价高且需要经常被实例化的对象,如大对象、需占用I/O的对象
等,这些对象在创建和销毁时会非常耗时,以及对象本身非常占内存的对象。
如果是简单的对象,对象的创建和销毁都非常迅速,也“不吃”内存;但有些对象,把它进行池化的时间比自己构建还多,这样就不划算了。因为对象池的管理本身也是需要占用资源的,如对象的创建、借用、归还这些都是需要消耗资源的。我们经常听到的(数据库)连接池、线程池用到的都是对象池机制的思想。