Python Memory错误解决方案,如果需要永久访问

时间:2012-06-06 15:04:36

标签: python memory python-2.7

首先,我知道SO上的Python内存错误问题的数量,但到目前为止,没有一个与我的用例匹配。

我目前正在尝试解析一堆文本文件(大约30 GB的~6k文件)并存储每个唯一的单词。是的,我正在建立一个单词表,不,我不打算用它做恶事,这是为大学。

我将找到的单词列表实现为一个集合(使用words = set([])创建,与words.add(word)一起使用)并且我只是将每个找到的单词添加到其中,考虑到设置的机制应删除所有重复项

这意味着我需要永久访问整个集合才能工作(或者至少我看不到其他选择,因为必须在每个插入时检查整个列表的重复项。)

现在,当我使用大约3.4 GB的RAM时,我遇到了大约25%的MemoryError。我在Linux 32bit上,所以我知道这个限制来自哪里,我的PC只有4 GAG的RAM,所以即使是64位也没有帮助。

我知道复杂性可能很糟糕(每个插入可能是O(n),虽然我不知道Python集是如何实现的(树?)),但它仍然(可能)更快并且(确切地说)比将每个单词添加到基元列表并在之后删除重复项更有效。

有没有办法让它运行?我期望大约6-10 GB的独特单词,所以使用我当前的RAM是不可能的,并且目前无法升级我的RAM(并且一旦我开始让这个脚本在大量文件上松动,就不能很好地扩展)

我目前唯一的想法是在磁盘上缓存(这将使进程更慢),或者将临时集写入磁盘并在之后合并它们,这将花费更多时间并且复杂性确实非常糟糕。是否有一个解决方案不会导致可怕的运行时间?

为了记录,这是我的完整资料来源。因为它仅供个人使用,所以非常可怕,但你明白了。

import os
import sys
words=set([])
lastperc = 0
current = 1
argl = 0
print "Searching for .txt-Files..."
for _,_,f in os.walk("."):
    for file in f:
        if file.endswith(".txt"):
            argl=argl+1
print "Found " + str(argl) + " Files. Beginning parsing process..."
print "0%                                              50%                                             100%"
for r,_,f in os.walk("."):
    for file in f:
        if file.endswith(".txt"):
            fobj = open(os.path.join(r,file),"r")
            for line in fobj:
                line = line.strip()
                word, sep, remains = line.partition(" ")
                if word != "":
                    words.add(word)
                word, sep, remains = remains.partition(" ")
                while sep != "":
                    words.add(word)
                    word, sep, remains2 = remains.partition(" ")
                    remains = remains2
                if remains != "":
                    words.add(remains)
            newperc = int(float(current)/argl*100)
            if newperc-lastperc > 0:
                for i in range(newperc-lastperc):
                    sys.stdout.write("=")
                    sys.stdout.flush()
            lastperc = newperc
            current = current+1
print ""
print "Done. Set contains " + str(len(words)) + " different words. Sorting..."
sorteddic = sorted(words, key=str.lower)
print "Sorted. Writing to File"
print "0%                                              50%                                             100%"
lastperc = 0
current = 1
sdicl = len(sorteddic)-1
fobj = open(sys.argv[1],"w")
for element in sorteddic:
    fobj.write(element+"\n")
    newperc = int(float(current)/sdicl*100)
    if newperc-lastperc > 0:
        for i in range(newperc-lastperc):
            sys.stdout.write("=")
            sys.stdout.flush()
    lastperc = newperc
    current = current+1
print ""
print "Done. Enjoy your wordlist."

感谢您的帮助和想法。

5 个答案:

答案 0 :(得分:3)

您可能需要将密钥存储在磁盘上。像Redis这样的键值存储可能符合要求。

答案 1 :(得分:2)

你真的是指6-10GB的独特单词吗?这是英文文本吗?当然,即使计算专有名词和名称,也不应该有超过几百万个独特的单词。

无论如何,我要做的是一次处理一个文件,或者一次处理一个文件的一个部分(比方说,100k),只为该部分构建一个唯一的单词列表。然后将所有集合合并为后处理步骤。

答案 2 :(得分:1)

我倾向于数据库表,但是如果你想留在一个框架中,请查看PyTables:http://www.pytables.org/moin

答案 3 :(得分:1)

我尝试的第一件事就是将单词限制为小写字符 - 正如Tyler Eaves指出的那样,这可能会减小设置大小以适应内存。以下是一些非常基本的代码:

import os
import fnmatch
import re

def find_files(path, pattern):
    for root, files, directories in os.walk(path):
        for f in fnmatch.filter(files, pattern):
            yield os.path.join(root, f)

words = set()
for file_name in find_files(".", "*.txt"):
    with open(file_name) as f:
        data = f.read()
    words.update(re.findall("\w+", data.lower()))

还有一些评论:

  1. 我通常希望字典在开头快速增长;在这个过程的后期应该找到很少的新单词,因此你的推断可能会严重高估单词列表的最终大小。

  2. 为此目的,集合非常有效。它们被实现为哈希表,并且添加新词的摊销复杂度为O(1)。

答案 4 :(得分:0)

将密钥散列到更小,更易于管理的代码空间中。将哈希键入包含具有该哈希的键的文件。哈希表小得多,个别密钥文件要小得多。