Ошибка памяти при работе с большим корпусом текста

У меня есть большой текстовый файл (~ 450 МБ -> 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

Я видел это, но я читаю файл построчно.


person ᴀʀᴍᴀɴ    schedule 21.12.2016    source источник


Ответы (2)


Чтобы проверить накладные расходы на структуру данных в вашем коде, я написал следующую тестовую программу. Предполагается, что ваш текстовый файл был размером N мегабайт в кодировке ASCII с относительно короткими строками. (Мне пришлось изменить 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 гигабайт памяти, поэтому часть памяти также не учтена. Возможны артефакты реализации 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 использовалось около 1 ГБ памяти. В C ++ нет sys.getsizeof(), поэтому требуется немного больше работы, чтобы разбить использование памяти, а я этого не делал.

Удвоение объема памяти эквивалентного C ++ на самом деле является довольно хорошим результатом для Python, поэтому я удаляю свои комментарии перед редактированием о реализации cPython.

Я думаю, ваша основная проблема заключается в хранении строки в виде массива коротких строк. Можно ли хранить строки как целые строки и разбивать их по мере необходимости, но не все сразу?

Какова конечная цель вашей программы?

person japreiss    schedule 21.12.2016
comment
К сожалению, каждая строка содержит от 100 до 1000 слов !! Как я могу усложнить свой код? - person ᴀʀᴍᴀɴ; 21.12.2016
comment
На самом деле, если я изменю свою программу на line = 10 * "the quick brown fox jumps over the lazy dog", использование памяти сильно сократится, даже для items. Это удивительно - я ожидал, что уменьшатся только накладные расходы dict и list. - person japreiss; 21.12.2016
comment
добавлено сравнение C ++ и новые выводы, см. правки. - person japreiss; 21.12.2016
comment
Мне нужно разбить строки, чтобы вычислить (TF-IDF) условия для всех строк, каждая строка - это документ - person ᴀʀᴍᴀɴ; 21.12.2016
comment
Ах хорошо. Каков общий объем словаря для всех документов? - person japreiss; 21.12.2016

memory error здесь растет, потому что даже если вы читаете свой файл построчно, вы сохраняете его содержимое в своем словаре docDict, то есть в памяти.

Я не знаю, что вы планируете делать с этим словарем, но я рекомендую выполнять этот процесс после каждой прочитанной строки, а затем сохранять результат в переменной (если процесс сильно сжимается) или прямо в файле или базе данных.

Надеюсь, я помог! Увидимся !

person Alexis Tacnet    schedule 21.12.2016