Python:itertools.product消耗太多资源
我创建了一个Python脚本,它通过字符排列生成一个单词列表。我正在使用Python:itertools.product消耗太多资源,python,permutation,itertools,Python,Permutation,Itertools,我创建了一个Python脚本,它通过字符排列生成一个单词列表。我正在使用itertools.product生成排列。我的字符列表由字母和数字组成01234567890abcdefghijklmnopqrstuvxyzabcdefghijklmnopqrstuvxyz。这是我的密码: #!/usr/bin/python import itertools, hashlib, math class Words: chars = '01234567890abcdefghijklmnopqrs
itertools.product
生成排列。我的字符列表由字母和数字组成01234567890abcdefghijklmnopqrstuvxyzabcdefghijklmnopqrstuvxyz。这是我的密码:
#!/usr/bin/python
import itertools, hashlib, math
class Words:
chars = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVXYZ'
def __init__(self, size):
self.make(size)
def getLenght(self, size):
res = []
for i in range(1, size+1):
res.append(math.pow(len(self.chars), i))
return sum(res)
def getMD5(self, text):
m = hashlib.md5()
m.update(text.encode('utf-8'))
return m.hexdigest()
def make(self, size):
file = open('res.txt', 'w+')
res = []
i = 1
for i in range(1, size+1):
prod = list(itertools.product(self.chars, repeat=i))
res = res + prod
j = 1
for r in res:
text = ''.join(r)
md5 = self.getMD5(text)
res = text+'\t'+md5
print(res + ' %.3f%%' % (j/float(self.getLenght(size))*100))
file.write(res+'\n')
j = j + 1
file.close()
Words(3)
此脚本适用于最多4个字符的单词列表。如果我尝试5或6个字符,我的计算机将消耗100%的CPU、100%的RAM并冻结
有没有办法限制这些资源的使用或优化这一繁重的处理过程?这能满足您的需要吗 我对make方法进行了所有更改:
def make(self, size):
with open('res.txt', 'w+') as file_: # file is a builtin function in python 2
# also, use with statements for files used on only a small block, it handles file closure even if an error is raised.
for i in range(1, size+1):
prod = itertools.product(self.chars, repeat=i)
for j, r in enumerate(prod):
text = ''.join(r)
md5 = self.getMD5(text)
res = text+'\t'+md5
print(res + ' %.3f%%' % ((j+1)/float(self.get_length(size))*100))
file_.write(res+'\n')
请注意,这仍然会占用千兆字节的内存,但不会占用虚拟内存
编辑:正如Padraic所指出的,Python3中没有file关键字,而且由于它是一个“坏的内置项”,所以不必太担心重写它。不过,我会在这里给它命名为file
编辑2:
要解释为什么这比以前的原始版本工作得更快更好,您需要知道惰性评估是如何工作的
假设我们有一个简单的表达式,如下所示(对于Python 3)(对于Python 2使用xrange):
这会立即将1万亿个元素计算到内存中,使内存溢出
因此,我们可以使用生成器来解决此问题:
a = (i for i in range(1e12))
在这里,没有对任何值进行评估,只是给出了解释程序关于如何评估它的说明。然后我们可以一个一个地迭代每个项目,并分别处理每个项目,因此在给定时间内存中几乎没有任何内容(一次只有一个整数)。这使得看似不可能的任务变得非常容易管理
itertools也是如此:它允许您通过使用迭代器而不是列表或数组来执行操作,从而实现高效、快速的内存操作
在您的示例中,您有62个字符,并且希望以5个重复或62**5(接近十亿个元素,或超过30 GB的ram)进行笛卡尔乘积。这个数字太大了。”
为了解决这个问题,我们可以使用迭代器
chars = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVXYZ'
for i in itertools.product(chars, repeat=5):
print(i)
在这里,在给定的时间内,只有笛卡尔乘积中的一个项在内存中,这意味着它非常高效
但是,如果您使用list()计算完整的迭代器,它会耗尽迭代器并将其添加到列表中,这意味着近10亿个组合突然再次出现在内存中。我们不需要一次将所有元素都存储在内存中:只需1。这是迭代器的强大功能
chars = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVXYZ'
for i in itertools.product(chars, repeat=5):
print(i)
以下是上的链接和另一个解释(对于3,大多数是正确的)。这是否符合您的要求 我对make方法进行了所有更改:
def make(self, size):
with open('res.txt', 'w+') as file_: # file is a builtin function in python 2
# also, use with statements for files used on only a small block, it handles file closure even if an error is raised.
for i in range(1, size+1):
prod = itertools.product(self.chars, repeat=i)
for j, r in enumerate(prod):
text = ''.join(r)
md5 = self.getMD5(text)
res = text+'\t'+md5
print(res + ' %.3f%%' % ((j+1)/float(self.get_length(size))*100))
file_.write(res+'\n')
请注意,这仍然会占用千兆字节的内存,但不会占用虚拟内存
编辑:正如Padraic所指出的,Python3中没有file关键字,而且由于它是一个“坏的内置项”,所以不必太担心重写它。尽管如此,我还是在这里给它命名为file
编辑2:
要解释为什么这比以前的原始版本工作得更快更好,您需要知道惰性评估是如何工作的
假设我们有一个简单的表达式,如下所示(对于Python 3)(对于Python 2使用xrange):
这会立即将1万亿个元素计算到内存中,使内存溢出
因此,我们可以使用生成器来解决此问题:
a = (i for i in range(1e12))
在这里,没有对任何值进行计算,只是给出了解释程序如何计算的说明。然后我们可以逐个迭代每个项,并分别对每个项进行处理,因此在给定时间内存中几乎没有任何内容(一次只有1个整数)。这使得看似不可能的任务非常容易管理
itertools也是如此:它允许您通过使用迭代器而不是列表或数组来执行操作,从而实现高效、快速的内存操作
在您的示例中,您有62个字符,并且希望以5个重复或62**5(接近10亿个元素,或超过30 GB的ram)进行笛卡尔乘积。这太大了。”
为了解决这个问题,我们可以使用迭代器
chars = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVXYZ'
for i in itertools.product(chars, repeat=5):
print(i)
在这里,在给定的时间内,只有笛卡尔乘积中的一个项在内存中,这意味着它非常高效
但是,如果您使用list()计算完整的迭代器,它将耗尽迭代器并将其添加到列表中,这意味着近10亿个组合突然再次出现在内存中。我们不需要同时在内存中存储所有元素:只有1个。这就是迭代器的威力
chars = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVXYZ'
for i in itertools.product(chars, repeat=5):
print(i)
以下是上的链接和另一个解释(对于3,大多数是正确的)。您的问题是呼叫列表,然后它会评估所有这些问题。Itertools非常适合惰性迭代,逐个评估它们以避免内存问题。您正在尝试使用5个字符(62**5)的近10亿个组合,这就是您的计算机冻结的原因。它消耗了所有可用的内存。你的建议是手动迭代?我会发布一个解决方案。您应该迭代每个元素。Itertools的工作原理与yield类似(虽然级别较低),但您可以这样想:它被赋予一组指令,然后计算一个值,并返回该值并冻结(因此没有内存积累)。然后你可以做任何事情,直到你需要下一个元素。将所有内容立即放在内存中会破坏使用itertools的目的,特别是对于这样的数据大小(~38 Gig的ram)。您应该在生成每个元素时对其进行评估,为每个元素执行工作,然后只保留您需要的内容。。您的问题是调用列表,然后该列表将对所有调用列表进行评估。Itertools非常适合惰性迭代,逐个评估它们以避免内存问题。您正在尝试使用5个字符(62**5)的近10亿个组合,这就是您的计算机冻结的原因。它消耗了所有可用的内存。你的建议是手动迭代?我会发布一个解决方案。您应该迭代每个元素。Itertools的工作原理与收益率相似(尽管较低)