我正在研究python内存管理算法和底层C代码,并测试了它的工作方式,获得了意外的结果。
基础:
使用多种方法在6 Gb RAM CentOS虚拟机上生成5.5 Gb字符串。生成是通过dict来完成的,在dict中,应该显示多少符号应进行多少次排序(例如{3: 5, 1: 3}
应该给出'11133333')。
期望:
''.join()
应该起作用,因为它使用memcpy(),并且它将使用的最大值是字符串的一部分,再加上iterable的下一部分。尽管dict
对象创建了缓冲区,但似乎可以很好地与swap配合使用。自定义可迭代对象的粒度将在速度和内存使用之间进行权衡。''.format()
实际上会释放内存,因此它应该工作得更快更好。s1+=s2
应该是最重的内存,因为它将两个字符串都保存在内存中并为新字符串创建一个缓冲区。结果:
一切均因MemoryError失败,除了:
-''.join()
,造粒最少
-...串联。
python -m dis pymemory.py
向我显示了“ INPLACE_ADD”以进行串联操作,该操作与我看过的C代码不兼容。
代码:
代码已被剥离,显然所有方法都应单独运行。
b = {
0: 590615000,
1: 591234001,
2: 590895000,
3: 590010000,
4: 591552000,
5: 590375000,
6: 589251000,
7: 589903000,
8: 590806000,
9: 590939000
}
# literal format
a = '{}{}{}{}{}{}{}{}{}{}'.format(str(0)*b[0], str(1)*b[1], str(2)*b[2], str(3)*b[3], str(4)*b[4], str(5)*b[5], str(6)*b[6], str(7)*b[7], str(8)*b[8], str(9)*b[9])
del a
# format
# MEMORY ERROR
d = {}
for k in b:
d['k'+str(k)] = str(k)*b[k]
a = ('{}'*d.keys().__len__()).format(*['{'+str(k)+'}' for k in sorted(d.keys())]).format(**d)
del a
del d
# join
# MEM ERROR
def i_am_iter(d):
for k in d:
yield str(k)*d[k]
raise StopIteration
a = ''.join(i_am_iter(b))
# concat
# WORKS!
a = ''
for k in b:
a += str(k)*b[k]
问题:
对此有解释吗?为什么串联有效?为什么不加入或格式化?我在某处缺少优化吗?
答案 0 :(得分:0)
好吧,所以事实证明,如果只有一个对对象的引用,就对concat进行了优化,这使它就位并且比大多数其他东西(联接和格式除外)和大多数内存消耗(包括联接和格式)快得多)。 http://blog.mclemon.io/python-efficient-string-concatenation-in-python-2016-edition https://docs.python.org/release/2.4.2/whatsnew/node12.html#SECTION0001210000000000000000