Python:itertools.product消耗了太多资源

时间:2015-12-05 02:06:29

标签: python permutation itertools

我创建了一个Python脚本,通过排列字符生成单词列表。我使用itertools.product生成我的排列。我的字符列表由字母和数字 01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVXYZ 组成。这是我的代码:

#!/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并冻结。

有没有办法限制这些资源的使用或优化这种繁重的处理?

1 个答案:

答案 0 :(得分:1)

这样做你想要的吗?

我在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所说,Python 3中没有文件关键字,因为它是一个“坏内置”,所以不要过于担心覆盖它。不过,我将这里命名为file_。

EDIT2:

要解释为什么它比以前的原始版本更快更好地工作,您需要知道 lazy 评估的工作原理。

假设我们有一个简单的表达式(对于Python 3)(对Python 2使用xrange):

a = [i for i in range(1e12)]

这会立即将1万亿个元素评估到内存中,从而溢出你的记忆。

所以我们可以使用生成器来解决这个问题:

a = (i for i in range(1e12))

这里没有评估任何值,只是给出了如何评估它的解释器说明。然后我们可以逐个遍历逐个项,并分别对每个项进行处理,因此在给定时间内几乎没有任何内容(一次只有1个整数)。这使得看似不可能完成的任务非常易于管理。

对于itertools也是如此:它允许您通过使用迭代器而不是列表或数组来执行操作来执行内存高效,快速的操作。

在你的例子中,你有62个字符,想要做5个重复的笛卡尔积,或62 ** 5(近10亿个元素,或超过30千兆字节的ram)。这太大了。“

为了解决这个问题,我们可以使用迭代器。

chars = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVXYZ'
for i in itertools.product(chars, repeat=5):
    print(i)

在这里,只有笛卡尔积中的一个项目在给定时间内存在内存中,这意味着它非常有效。

但是,如果使用list()计算完整的迭代器,它会耗尽迭代器并将其添加到列表中,这意味着将近10亿个组合突然再次出现在内存中。我们不需要同时在内存中的所有元素:只是1.迭代器的力量。

以下是itertools module的链接和iterators in Python 2的其他解释(大部分为3)。