[英]Memory management for python scripts
因此,我正在尝试解决python中Euler项目中的一些问题。 我目前正在研究问题92 (方形数字链)。 基本上,这个想法是,如果您采用任何整数,然后对它的组成位数进行平方(例如42 = 4 2 + 2 2 = 20,然后2 2 + 0 2 = 4,依此类推),则您总是以1或2结束。 89。
我正在尝试编写一个程序,该程序可以计算在1到10 K范围内将有多少个数字以89结尾,有多少将以1结尾。许多。 目标是能够做到最大可能的K。 (对于那些好奇的人来说,这是Hackerrank的挑战)。
为了在我的一生中做大量工作,我需要使用缓存。 但这是缓存(最终会占用大量RAM)和计算时间之间的平衡。
我的问题是我最终用尽了内存。 因此,我试图限制正在使用的缓存的长度。 但是,我仍然用光了内存。 我似乎无法找到导致我内存不足的原因。
我正在ubuntu 14.04 LTS的pycharm上运行它。
我的问题:
有没有一种方法来检查什么是占用了我的内存? 是否有一些工具(或脚本)可以让我从根本上监视程序中变量的内存使用? 或者假设我的RAM用完了一定是错误的,这一定是因为程序中的某些变量太大了吗? 我必须承认,我对程序中内存使用的详细细节还不是很清楚。
编辑:当K = 8时,我用完了mem,所以对于最大为10 8的整数,它不是那么大。 另外,我在10 8之前进行了测试(所以10 7终止了,但是要花一些时间,并且比较小的计算使用更多的内存)。 而且似乎没有限制我的缓存大小变量有什么区别.....
我建议测试各种缓存大小,以查看拥有尽可能大的缓存是否真正有益。
如果采用任何10位数字并计算其数字的平方和,则总和最多为10 * 9 * 9 =810。因此,如果将结果缓存为1到810,那么您应该能够处理所有4到10位之间的数字而无需递归。
这样,我在大约6分钟内处理了前10个8 ^数字,而内存使用量则保持在大约10 MB的恒定值。
这是Mathias Rav的出色创意的一种变体,但是保留了使用带有记忆的递归函数的想法。 这个想法是使用辅助函数来完成繁重的工作,而主要函数只是执行迭代的第一步。 第一步将问题的大小减小到可以使用缓存的大小。 缓存仍然很小。 我能够在大约10分钟内完成所有数字,直到10 ** 8(由于递归的开销,使得该解决方案比Mathias的解决方案效率低):
cache = {}
def helper(n):
if n == 1 or n == 89:
return n
elif n in cache:
return cache[n]
else:
ss = sum(int(d)**2 for d in str(n))
v = helper(ss)
cache[n] = v
return v
def f(n):
ss = sum(int(d)**2 for d in str(n))
return helper(ss)
def freq89(n):
total = 0
for i in range(1,n+1):
if f(i) == 89: total += 1
return total/n
这是Mathias Rav和John Coleman对答案的扩展评论。 我打算将其作为社区Wiki的答案。 约翰·科尔曼说不要这样做,所以我不是。
我将从约翰·科尔曼的答案开始。
cache = {}
def helper(n):
if n == 1 or n == 89:
return n
elif n in cache:
return cache[n]
else:
ss = sum(int(d)**2 for d in str(n))
v = helper(ss)
cache[n] = v
return v
def f(n):
ss = sum(int(d)**2 for d in str(n))
return helper(ss)
一个可以加快速度的小事情是,通过将cache
初始化为{1:some_value, 89:some_other_value}
来避免if
在helper(n)
。 明显的初始化是{1:1, 89:89}
。 一个不太明显但最终更快的初始化方法是{1:False, 89:True}
。 这样可以将if f(i) == 89: total += 1
更改为if f(i): total += 1
。
另一个可能有用的小事情是摆脱递归。 这里不是这样。 为了摆脱递归,我们必须按照以下方式做一些事情
def helper(n):
l = []
while n not in cache :
l.append(n)
n = sum(int(d)**2 for d in str(n))
v = cache[n]
for k in l :
cache[k] = v
return v
问题是,几乎所有遇到的编号f(n)
将已经缓存感谢如何helper
从被称为f(n)
摆脱递归会不必要地创建一个空列表,需要对其进行垃圾回收。
约翰·科尔曼(John Coleman)的答案最大的问题是,通过sum(int(d)**2 for d in str(n))
计算数字平方sum(int(d)**2 for d in str(n))
。 虽然非常pythonic,但这非常昂贵。 我将从将helper
和f
的变量ss
更改为一个函数开始:
def ss(n):
return sum(int(d)**2 for d in str(n))
仅此一项就无法提高性能。 实际上,这会损害性能。 函数调用在python中很昂贵。 通过将此功能设为函数,我们可以通过用整数算术替换字符串操作来做一些非Python的事情:
def ss(n):
s = 0
while n != 0:
d = n % 10
n = n // 10
s += d**2
return s
这里的加速非常重要。 我的计算时间减少了30%。 那不是很好 还有一个问题,就是使用幂运算符。 除了Fortran和Matlab以外,几乎所有语言都使用d*d
比d**2
快得多。 在python中肯定是这种情况。 这项简单的更改将执行时间减少了30%,而执行时间却减少了近一半。
将所有这些放在一起产生
cache = {1:False, 89:True}
def ss (n):
s = 0
while n != 0:
d = n % 10
n = n // 10
s += d*d
return s
def helper(n):
if n in cache:
return cache[n]
else:
v = helper(ss(n))
cache[n] = v
return v
def f(n):
return helper(ss(n))
def freq89(n):
total = 0
for i in range(1,n+1):
if f(i): total += 1
return total/n
print (freq89(int(1e7)))
我尚未利用Mathias Rav的回答。 在这种情况下,摆脱递归将是有意义的。 它还有助于将循环嵌入初始化缓存的函数的初始范围内(在python中,函数调用非常昂贵)。
N = int(1e7)
cache = {1:False, 89:True}
def ss(n):
s = 0
while n != 0:
d = n % 10
n //= 10
s += d*d
return s
def initialize_cache(maxsum):
for n in range(1,maxsum+1):
l = []
while n not in cache:
l.append(n)
n = ss(n)
v = cache[n]
for k in l:
cache[k] = v
def freq89(n):
total = 0
for i in range(1,n):
if cache[ss(i)]:
total += 1
return total/n
maxsum = 81*len(str(N-1))
initialize_cache(maxsum)
print (freq89(N))
上面的内容(在我的计算机上)大约需要16.5秒才能计算出我的计算机上1(含)和10000000(不含)之间的数字比率。 这几乎比初始版本(44.7秒)快三倍。 以上计算需要花费三分钟多的时间来计算1(含)和1e8(不含)之间的数字比率。
事实证明我还没有完成。 程序仅对12345678进行计算时,就无需按位数计算(例如)12345679的数字平方和。缩短十个用例中九个用例的计算时间的捷径便得到了回报。 函数ss(n)
变得更加复杂:
prevn = 0
prevd = 0
prevs = 0
def ss(n):
global prevn, prevd, prevs
d = n % 10
if (n == prevn+1) and (d == prevd+1):
s = prevs + 2*prevd + 1
prevs = s
prevn = n
prevd = d
return s
s = 0
prevn = n
prevd = d
while n != 0:
d = n % 10
n //= 10
s += d*d
prevs = s
return s
这样,计算(不包括)1e7之前的数字的比率需要6.6秒,对于不包括1e8的数字要计算68秒。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.