处理大型文本语料库时出现内存错误



我有一个大文本文件(~450MB -> 129,000 行和 457,000,000 个字符),当我尝试使用这个文件一段时间后,Memory Error上升,这是我的代码:

docDict = {}
ind = 1
with open('somefile.txt',encoding='utf-8') as f:
for line in f:
data = line.split(' ')
docDict[ind] = data
ind+=1

我看到了这个,但我逐行阅读文件。

为了测试代码中数据结构的开销,我编写了以下测试程序。它假定您的文本文件以 ASCII 编码N兆字节,行相对较短。(在我的物理内存耗尽后,我不得不将N从 450 更改为 150。

import sys
MB = 1024 * 1024
line = "the quick brown fox jumps over the lazy dog"
megs = 150
nlines = (megs * MB) / len(line)
d = {}
for i in xrange(nlines):
d[i] = line.split(' ')
dict_size = sys.getsizeof(d)
list_size = sum(sys.getsizeof(a) for a in d.items())
item_size = sum(sum(sys.getsizeof(s) for s in a) for a in d.items())
print " dict:", dict_size / float(MB), "MB"
print "lists:", list_size / float(MB), "MB"
print "items:", item_size / float(MB), "MB"
print "total:", (dict_size + list_size + item_size) / float(MB), "MB"

结果是:

dict: 192.00 MB
lists: 251.16 MB
items: 669.77 MB
total: 1112.9 MB

观察活动监视器,Python 进程的内存使用量超过 2 GB,因此也有一些内存未被考虑在内。malloc实现的工件可能是可能的。

我在C++年实现了相同的程序:

#include <string>
#include <vector>
#include <unordered_map>
int main()
{
int const MB = 1024 * 1024;
std::string const line = "the quick brown fox jumps over the lazy dog";
std::vector<std::string> const split = {
"the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"
};
int const megs = 150;
int const nlines = (megs * MB) / line.size();
std::unordered_map<int, std::vector<std::string>> d;
for (int i = 0; i < nlines; ++i) {
d[i] = split;
}
}

clang++ -O3编译,这使用了大约1GB的内存。C++没有sys.getsizeof()所以需要更多的工作来分解内存使用情况,而我没有做这项工作。

对于 Python 来说,两倍的等效C++内存实际上是一个相当不错的结果,所以我删除了关于 cPython 实现的预编辑注释。

我认为您的主要问题是将行存储为短字符串数组。您是否可以将行存储为整个字符串并根据需要拆分它们,但不能一次全部拆分?

您的计划的最终目标是什么?

memory error在这里引发,因为即使您逐行读取文件,也会将其内容存储在字典docDict中,因此存储在内存中。

我不知道你打算用这个字典做什么,但我建议在你阅读的每一行之后做这个过程,然后将结果存储在一个变量中(如果这个过程压缩了很多),或者直接存储在文件或数据库中。

希望我有帮助!再见!

最新更新