python - 高效增长的对象池
问题描述
是否有已建立的模块或良好实践可以有效地处理 Python 3 中的大型对象池?
我所说的“对象池”是指某个类能够:
- 获取指定类型的新实例,同时在必要时动态扩展内存分配;
- 为先前获取的对象维护一致的索引。
这是一个基本示例:
class Value:
__slots__ = ('a','b')
def __init__(self,a=None,b=None):
self.a = a
self.b = b
class BasicPool:
def __init__(self):
self.data = []
def __getitem__(self,k):
return self.data[k]
def fetch(self):
v = Value()
self.data.append(v)
return v
class BlockPool:
def __init__(self,bsize=100):
self.bsize = bsize
self.next = bsize
self.data = []
def __getitem__(self,k):
b,k = divmod(k,self.bsize)
return self.data[b][k]
def fetch(self):
self.next += 1
if self.next >= self.bsize:
self.data.append([ Value() for _ in range(self.bsize) ])
self.next = 0
return self.data[-1][self.next]
BasicPool
没有做任何聪明的事情:每当请求一个新实例时,它都会被实例化并附加到底层的list
. 另一方面,BlockPool
增长了一个预先分配的实例块列表。但令人惊讶的是,预分配在实践中似乎没有好处:
from timeit import default_timer as timer
def benchmark(P):
N = int(1e6)
start = timer()
for _ in range(N): P.fetch()
print( timer() - start )
print( 'Basic pool:' )
for _ in range(5): benchmark(BasicPool())
# Basic pool:
# 1.2352294209995307
# 0.5003506309985823
# 0.48115064000012353
# 0.48508202800076106
# 1.1760561199989752
print( 'Block pool:' )
for _ in range(5): benchmark(BlockPool())
# Block pool:
# 0.7272855400005938
# 1.4875716509995982
# 0.726611527003115
# 0.7369502859983186
# 1.4867010340021807
如您所见,BasicPool
总是比BlockPool
(我也不知道这些大变化的原因)。对象池必须是 Python 中相当普遍的需求;真的是使用内置的最好方法list.append
吗?是否有更智能的容器可用于进一步提高运行时性能,或者这是否由实例化时间主导?
解决方案
基于 a 的数组的几何增长的重点list
是将重新分配开销减少到一个常数因子。该常数可以很容易地小于手动制作块的常数(主要是因为后者的缓慢、解释性操作self.next
)self.data
。(渐近地说,当然,成本仍然是BlockPool.fetch
。)append
此外,您的基准不包括破坏块的额外成本,也不包括读取时的两步索引。
所以list
肯定和它一样好(无需编写自己的 C 代码)。您可以通过继承而不是包含一个来改进BasicPool
一点,完全消除字典查找和解释包装器。list
fetch
__getitem__
推荐阅读
- ffmpeg - 视频显示/解码/编码程序如何支持 ARM GPU?
- swift - Swift:将图像添加到 CALayer 返回黑色
- dropdown - rselenium 截图显示与实际不同
- ansible - Ansible errros out when daemon_reload=yes with error failure 1 during daemon-reload: Failed to execute operation: Connection timed out
- codeigniter-3 - 更新文件pdf时Codeigniter取消链接不起作用
- python - 在python中更新类属性的正确方法?
- javascript - 如何将参数传递给带有处理程序的函数?
- c++ - 用 Qt 连接 CLion
- elasticsearch - 复杂的弹性搜索查询
- python - 这个 \n 来自我的数组(Python)中的哪里?