Python 2.7 复杂度过大导致内存错误
我刚接触Python,正在运行以下代码,但在使用Python 2.7时出现了内存错误。因为我在用OpenCV,所以我选择了Python 2.7。我看过之前的帖子,但对它们的内容不是很理解。
s={}
ns={}
ts={}
for i in range(0,256): #for red component
for j in range(0,256): #for green component
for k in range(0,256): # for blue component
s[(i,j,k)]=0
ns[(i,j,k)]=0
ts[(i,j,k)]=i*j*k
请帮帮我。这个代码是想记录红色、绿色和蓝色成分的频率。为此,我把这些值初始化为零。
3 个回答
即使你所有的变量都只用一个字节,这个程序也需要405MB的内存。
你应该使用压缩技术来在有限的空间里存储更多的数据。
补充:如果你想在Python中制作直方图,可以参考这个很不错的例子,使用的是Python图像库(PIL):点击这里查看。实际上,主要的工作只需要这三行代码:
import Image
img = Image.open(imagepath)
hist = img.histogram()
实际上,你的程序至少需要 300*300*300*4*3 字节的内存,仅仅是为了字典中的值数据。此外,你的键元组还占用 300*300*300*3*3*4 字节。
总共加起来是 1296000000 字节,或者说 1.2 GiB 的数据。
这个计算还没有包括维护字典数据时的额外开销。
所以,程序是否会出错,取决于你电脑的内存有多少。
你可以先尝试这样做:
s = {}
ns = {}
ts = {}
for i in range(0, 300):
for j in range(0, 300):
for k in range(0, 300):
index=(i, j, k)
s[index]=j
ns[index]=k
ts[index]=i*j*k
理论上,这样做只会占用一半的内存,因为数据部分的内存减少了,而索引元组是可以重复使用的。
根据你描述的情况(你只是想计数),其实不需要预先初始化所有可能的组合。所以你可以省略你问题中提到的初始化,而是建立一个只存储实际有数据的值的存储,这些值通常会比所有可能的组合要少得多。
你可以使用一个 defaultdict()
,或者手动模仿它的行为,因为我觉得你颜色“调色板”中的大多数组合并不会被用到。
from collections import defaultdict
make0 = lambda: 0
s = defaultdict(make0)
ns = defaultdict(make0)
# what is ts? do you need it?
现在你有三个类似 dict
的对象,可以根据需要写入数据。然后,对于你实际拥有的每一种颜色组合,你可以执行 s[index] += 1
或者 ns[index] += 1
。
至于你的 ts
,我不太清楚,也许你可以计算出来,或者需要找到其他解决方案。
第一点:用 itertools
替代每次循环都构建的 range
列表。xrange
会返回一个迭代器对象,和 range
类似,而 product
会返回一个迭代器,从给定的可迭代对象中选择元组元素。
第二点:对于大数据,使用 numpy
。它是专门为这种情况设计的矩阵实现。
>>> import numpy as np
>>> from itertools import product
>>> x=np.zeros((256,256,256))
>>> for i, j, k in product(xrange(256), repeat=3):
... x[i,j,k]= i*j*k
...
对我来说,大约需要五秒钟,内存使用量也在预期范围内。
$ cat /proc/27240/status
Name: python
State: S (sleeping)
...
VmPeak: 420808 kB
VmSize: 289732 kB
注意,如果你尝试分配三个 256*256*256 的数组,可能会遇到系统内存限制,因为每个数组大约有1700万条数据。幸运的是,numpy 允许你将数组保存到磁盘上。
你听说过 PIL(Python图像库) 吗?你可能会觉得它很有用。