Python脚本在完成后很长时间后不会终止

dog*_*anb 4 python

我有一个奇怪的问题。我正在加载一个巨大的文件(3.5G)并从中制作字典并进行一些处理。一切完成后,我的脚本不会立即终止,它会在一段时间后终止。我认为这可能是由于内存释放,还有什么其他原因??我很感激任何意见。我怎样才能让我的脚本运行得更快?

下面是对应的代码:

类文件处理器:

    def __init__(self):
            self.huge_file_dict = self.upload_huge_file()


    def upload_huge_file(self):
            d = defaultdict(list)
            f=  codecs.open('huge_file', 'r',  encoding='utf-8').readlines()
            for line in f:
                    l = line.strip()
                    x,y,z,rb,t = l.split()
                    d[rb].append((x,y,z,t))
            return d

    def do_some_processing(self, word):
           if word in self.huge_file_dict:
                    do sth with  self.huge_file_dict[word]
Run Code Online (Sandbox Code Playgroud)

aba*_*ert 6

我的猜测是你可怕的减速,直到你的程序完成后才会恢复,这是由于使用了比你实际拥有的更多的内存,这导致你的操作系统开始将 VM 页面交换到磁盘和交换到磁盘。一旦发生足够多的交换,您最终会陷入“交换地狱”,其中很大一部分内存访问涉及磁盘读取甚至磁盘写入,这需要更多的时间,并且您的系统直到几秒钟后,您终于释放了所有内存。

显而易见的解决方案是不使用太多内存。

tzaman 的回答, 避免readlines(),将消除一些记忆。一个 3.5GB 文件中所有行的巨大列表在 Python 3.4 或 2.7 上至少需要 3.5GB(但实际上至少比这多 20%),在 3.0-3.3 上可能是 2x 或 4x。

但是 dict 将比列表更大,您需要它,对吗?

嗯,不,你可能没有。将 dict 保存在磁盘上并根据需要获取值可能听起来很慢,但如果虚拟内存必须不断与磁盘来回交换,它可能仍然比将其保存在虚拟内存中快得多。

您可能需要考虑使用一个简单的dbm或更强大的键值数据库(某些选项的谷歌“NoSQL 键值”),或者sqlite3数据库,甚至是像 MySQL 这样的基于服务器的 SQL 数据库。

或者,如果您可以将所有内容保存在内存中,但以更紧凑的形式保存,那就是两全其美。

我注意到在您的示例代码中,您对 dict 所做的唯一一件事就是检查word in self.huge_file_dict. 如果这是真的,那么您可以使用 aset而不是 adict并且不将所有这些值保留在内存中。这应该会减少大约 80% 的内存使用。

如果您经常需要键,但偶尔需要值,您可能需要考虑一个 dict,它只是将键映射到索引中,您可以根据需要从磁盘中读取某些内容(例如,具有固定长度字符串的文件,您可以然后mmap切片)。

或者,您可以将值粘贴在 Pandas 框架中,这将比原生 Python 存储更紧凑一些——可能足以发挥作用——并使用字典将键映射到索引。

最后,您可以减少交换量而不实际减少内存量。将一个巨大的排序列表一分为二,而不是访问一个巨大的字典,可能会——取决于你的单词模式——提供更好的记忆位置。