Почему загрузка этого файла занимает столько памяти? - PullRequest
5 голосов
/ 20 мая 2011

Попытка загрузить файл в python. Это очень большой файл (1,5 ГБ), но у меня есть доступная память, и я просто хочу сделать это один раз (поэтому при использовании python мне просто нужно отсортировать файл один раз, чтобы python был легким выбором).

Моя проблема заключается в том, что загрузка этого файла приводит к значительному значительному использованию памяти. Когда я загрузил около 10% строк в память, Python уже использует 700 МБ, что явно слишком много. Примерно на 50% скрипт зависает, используя 3,03 Гб реальной памяти (и медленно растет).

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

print 'Loading file into memory'
input_file = open(input_file_name, 'r')
input_file.readline() # Toss out the header
lines = []
totalLines = 31164015.0
currentLine = 0.0
printEvery100000 = 0
for line in input_file:
    currentLine += 1.0
    lined = line.split('\t')
    printEvery100000 += 1
    if printEvery100000 == 100000:
        print str(currentLine / totalLines)
        printEvery100000 = 0;
    lines.append( (lined[timestamp_pos].strip(), lined[personID_pos].strip(), lined[x_pos].strip(), lined[y_pos].strip()) )
input_file.close()
print 'Done loading file into memory'

РЕДАКТИРОВАТЬ: В случае, если кто-то не уверен, общее мнение, как представляется, заключается в том, что каждая выделенная переменная съедает все больше и больше памяти. В этом случае я «исправил» это путем 1) вызова readLines (), который по-прежнему загружает все данные, но имеет только одну строковую переменную для каждой строки. Это загружает весь файл, используя около 1,7 Гб. Затем, когда я вызываю lines.sort (), я передаю функцию клавише, которая разделяется на вкладках и возвращает правильное значение столбца, преобразованное в int. Это медленно в вычислительном отношении и в целом требует много памяти, но работает. Сегодня много узнал о распределении переменных: D

Ответы [ 2 ]

3 голосов
/ 20 мая 2011

Вот приблизительная оценка необходимой памяти, основанная на константах, полученных из вашего примера.Как минимум, вам нужно вычислить издержки внутреннего объекта Python для каждой строки разбиения, а также накладные расходы для каждой строки.

По оценкам 9.1 GB для сохранения файла в памяти, при условии, что следующие константы, которые отключенынемного, так как вы используете только часть каждой строки:

  • 1,5 ГБ размер файла
  • 31 164 015 всего строк
  • каждая строка разбита на список с4 штуки

Код:

import sys
def sizeof(lst):
    return sys.getsizeof(lst) + sum(sys.getsizeof(v) for v in lst)

GIG = 1024**3
file_size = 1.5 * GIG
lines = 31164015
num_cols = 4
avg_line_len = int(file_size / float(lines))

val = 'a' * (avg_line_len / num_cols)
lst = [val] * num_cols

line_size = sizeof(lst)
print 'avg line size: %d bytes' % line_size
print 'approx. memory needed: %.1f GB' % ((line_size * lines) / float(GIG))

Возвращает:

avg line size: 312 bytes
approx. memory needed: 9.1 GB
1 голос
/ 20 мая 2011

Я не знаю об анализе использования памяти, но вы можете попробовать это, чтобы заставить его работать без нехватки памяти. Вы разберетесь в новом файле, доступ к которому осуществляется с помощью сопоставления памяти (я был уверен, что это будет работать эффективно [с точки зрения памяти]). В Mmap есть некоторые специфичные для ОС работы, я тестировал это в Linux (очень маленький масштаб).

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

Вы можете найти алгоритм бинарного поиска в файле в этом вопросе .

Надеемся, эффективный способ сортировки массивного файла построчно:

import os
from mmap import mmap

input_file = open('unsorted.txt', 'r')
output_file = open('sorted.txt', 'w+')

# need to provide something in order to be able to mmap the file
# so we'll just copy the first line over
output_file.write(input_file.readline())
output_file.flush()
mm = mmap(output_file.fileno(), os.stat(output_file.name).st_size)
cur_size = mm.size()

for line in input_file:
  mm.seek(0)
  tup = line.split("\t")
  while True:
    cur_loc = mm.tell()
    o_line = mm.readline()
    o_tup = o_line.split("\t")
    if o_line == '' or tup[0] < o_tup[0]: # EOF or we found our spot
      mm.resize(cur_size + len(line))
      mm[cur_loc+len(line):] = mm[cur_loc:cur_size]
      mm[cur_loc:cur_loc+len(line)] = line
      cur_size += len(line)
      break
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...