有没有办法避免这种内存错误?

时间:2013-04-18 19:46:54

标签: python memory pypy

我目前正在解决Project Euler上的问题,到目前为止,我已经提出了这个问题的代码。

from itertools import combinations
import time

def findanums(n):
    l = []
    for i in range(1, n + 1):
        s = []
        for j in range(1, i):
            if i % j == 0:
                s.append(j)
        if sum(s) > i:
            l.append(i)
    return l

start = time.time() #start time

limit = 28123

anums = findanums(limit + 1) #abundant numbers (1..limit)
print "done finding abundants", time.time() - start

pairs = combinations(anums, 2)
print "done finding combinations", time.time() - start

sums = map(lambda x: x[0]+x[1], pairs)
print "done finding all possible sums", time.time() - start

print "start main loop"
answer = 0
for i in range(1,limit+1):
    if i not in sums:
        answer += i
print "ANSWER:",answer

当我跑步时,我遇到了MemoryError

追溯:

File "test.py", line 20, in <module>
    sums = map(lambda x: x[0]+x[1], pairs)

我试图通过从我从谷歌那里获得的垃圾收集来禁止它,但无济于事。我是以错误的方式接近这个吗?在我看来,这感觉就像是最自然的方式,而且我现在处于亏损状态。

SIDE注意:我正在使用PyPy 2.0 Beta2(Python 2.7.4),因为它比我使用过的任何其他python实现都要快得多,而Scipy / Numpy也在我脑海中,因为我还没刚开始编程,我没有工程或强大的数学背景。

3 个答案:

答案 0 :(得分:4)

正如凯文在评论中提到的,你的算法可能是错误的,但无论如何你的代码都没有优化。

使用非常大的列表时,通常使用generators,有一个着名的,很棒的Stackoverflow答案,解释了yieldgenerator - What does the "yield" keyword do in Python? <的概念/ p>

问题是您的pairs = combinations(anums, 2)不会生成generator,但会生成一个占用大量内存的大对象。

我更改了您的代码以使用此功能,因为您只对集合进行一次迭代,您可以懒惰地评估值:

def generator_sol(anums1, s):
      for comb in itertools.combinations(anums1, s):
        yield comb

现在而不是生成大对象的pairs = combinations(anums, 2)。 使用:

pairs = generator_sol(anums, 2)

然后,我会使用另一个lambda

而不是generator
sums_sol = (x[0]+x[1] for x in pairs)

另一个提示,你最好看看xrange哪个更合适,它不会生成一个列表但是xrange object在许多情况下更有效(例如这里)。

答案 1 :(得分:2)

我建议您使用generators。尝试更改此内容:

sums = map(lambda x: x[0]+x[1], pairs)

sums = (a+b for (a,b) in pairs)

Ofiris解决方案也可以,但暗示itertools.combinations在错误时返回列表。如果您要继续解决项目问题,请查看itertools documentation

答案 2 :(得分:1)

问题在于anums很大 - 大约28000个元素。所以对必须是28000 * 28000 * 8字节= 6GB。如果您使用numpy,您可以将anums转换为numpy.int16数组,在这种情况下,结果对将为1.5GB - 更易于管理:

import numpy as np
#cast
anums = np.array([anums],dtype=np.int16)
#compute the sum of all the pairs via outer product
pairs = (anums + anums.T).ravel()