Подтвердить что ты не робот

Предел верхней памяти?

Есть ли ограничение для памяти для python? Я использовал python script для вычисления средних значений из файла размером минимум 150 МБ.

В зависимости от размера файла я иногда сталкиваюсь с MemoryError.

Можно ли назначить больше памяти для python, чтобы я не сталкивался с ошибкой?


EDIT: код ниже

ПРИМЕЧАНИЕ. Размеры файлов могут сильно различаться (до 20 ГБ), минимальный размер файла - 150 МБ.

file_A1_B1 = open("A1_B1_100000.txt", "r")
file_A2_B2 = open("A2_B2_100000.txt", "r")
file_A1_B2 = open("A1_B2_100000.txt", "r")
file_A2_B1 = open("A2_B1_100000.txt", "r")
file_write = open ("average_generations.txt", "w")
mutation_average = open("mutation_average", "w")

files = [file_A2_B2,file_A2_B2,file_A1_B2,file_A2_B1]

for u in files:
    line = u.readlines()
    list_of_lines = []
    for i in line:
        values = i.split('\t')
        list_of_lines.append(values)

    count = 0
    for j in list_of_lines:
        count +=1

    for k in range(0,count):
        list_of_lines[k].remove('\n')

    length = len(list_of_lines[0])
    print_counter = 4

    for o in range(0,length):
        total = 0
        for p in range(0,count):
            number = float(list_of_lines[p][o])
            total = total + number
        average = total/count
        print average
        if print_counter == 4:
            file_write.write(str(average)+'\n')
            print_counter = 0
        print_counter +=1
file_write.write('\n')
4b9b3361

Ответ 1

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

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

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

Пределы памяти Python определяются тем, сколько физического дискового пространства и виртуальной памяти на вашем компьютере и операционной системе доступно. Даже если вы не используете все это, и ваша программа "работает", использование этого может быть непрактичным, потому что оно занимает слишком много времени.

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

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

try:
    from itertools import izip_longest
except ImportError:    # Python 3
    from itertools import zip_longest as izip_longest

GROUP_SIZE = 4
input_file_names = ["A1_B1_100000.txt", "A2_B2_100000.txt", "A1_B2_100000.txt",
                    "A2_B1_100000.txt"]
file_write = open("average_generations.txt", 'w')
mutation_average = open("mutation_average", 'w')  # left in, but nothing written

for file_name in input_file_names:
    with open(file_name, 'r') as input_file:
        print('processing file: {}'.format(file_name))

        totals = []
        for count, fields in enumerate((line.split('\t') for line in input_file), 1):
            totals = [sum(values) for values in
                        izip_longest(totals, map(float, fields), fillvalue=0)]
        averages = [total/count for total in totals]

        for print_counter, average in enumerate(averages):
            print('  {:9.4f}'.format(average))
            if print_counter % GROUP_SIZE == 0:
                file_write.write(str(average)+'\n')

file_write.write('\n')
file_write.close()
mutation_average.close()

Ответ 2

Вы читаете весь файл в памяти (line = u.readlines()), который, конечно, не удастся, если файл слишком большой (и вы говорите, что некоторые из них до 20 ГБ), так что ваша проблема там.

Лучше итерации по каждой строке:

for current_line in u:
    do_something_with(current_line)

- рекомендуемый подход.

Позже в script вы выполняете очень странные вещи, например, сначала подсчитываете все элементы в списке, а затем конструируете цикл for по диапазону этого числа. Почему бы не перебрать список напрямую? Какова цель вашего script? У меня сложилось впечатление, что это можно сделать гораздо проще.

Это одно из преимуществ высокоуровневых языков, таких как Python (в отличие от C, где вам нужно выполнять эти домашние задачи самостоятельно): разрешить Python обрабатывать итерацию для вас и собирать в памяти то, что вам действительно нужно иметь в памяти в любой момент времени.

Кроме того, по-видимому, вы обрабатываете TSV файлы (значения, разделенные табулированными), вы должны взглянуть на csv module, который будет обрабатывать все расщепления, удаление \n и т.д. для вас.

Ответ 3

Python может использовать всю память, доступную для своей среды. Мой простой "тест памяти" сбой на ActiveState Python 2.6 после использования

1959167 [MiB]

В jython 2.5 он срабатывает раньше:

 239000 [MiB]

Возможно, я смогу настроить Jython на использование большего объема памяти (он использует ограничения из JVM)

Тестовое приложение:

import sys

sl = []
i = 0
# some magic 1024 - overhead of string object
fill_size = 1024
if sys.version.startswith('2.7'):
    fill_size = 1003
if sys.version.startswith('3'):
    fill_size = 497
print(fill_size)
MiB = 0
while True:
    s = str(i).zfill(fill_size)
    sl.append(s)
    if i == 0:
        try:
            sys.stderr.write('size of one string %d\n' % (sys.getsizeof(s)))
        except AttributeError:
            pass
    i += 1
    if i % 1024 == 0:
        MiB += 1
        if MiB % 25 == 0:
            sys.stderr.write('%d [MiB]\n' % (MiB))

В вашем приложении вы сразу читаете весь файл. Для таких больших файлов вы должны читать строки за строкой.

Ответ 4

Нет, нет ограничения на использование Python для использования памяти в Python. Я регулярно работаю с приложениями Python, которые могут использовать несколько гигабайт памяти. Скорее всего, ваш script фактически использует больше памяти, чем доступно на компьютере, на котором вы работаете.

В этом случае решение состоит в том, чтобы перезаписать script для большей эффективности памяти или добавить больше физической памяти, если script уже оптимизирован для минимизации использования памяти.

Edit:

Ваш script считывает все содержимое ваших файлов в память сразу (line = u.readlines()). Поскольку вы обрабатываете файлы размером до 20 ГБ, вы получите ошибки памяти с этим подходом, если у вас нет огромного объема памяти на вашем компьютере.

Лучшим подходом было бы чтение файлов по одной строке за раз:

for u in files:
     for line in u: # This will iterate over each line in the file
         # Read values from the line, do necessary calculations

Ответ 5

Вы не только читаете весь каждый файл в памяти, но и тщательно обрабатываете информацию в таблице с именем list_of_lines.

У вас есть вторичная проблема: ваши варианты имен переменных сильно обфускают то, что вы делаете.

Вот ваш script, переписанный с помощью caplines readlines() и со значимыми именами:

file_A1_B1 = open("A1_B1_100000.txt", "r")
file_A2_B2 = open("A2_B2_100000.txt", "r")
file_A1_B2 = open("A1_B2_100000.txt", "r")
file_A2_B1 = open("A2_B1_100000.txt", "r")
file_write = open ("average_generations.txt", "w")
mutation_average = open("mutation_average", "w") # not used
files = [file_A2_B2,file_A2_B2,file_A1_B2,file_A2_B1]
for afile in files:
    table = []
    for aline in afile:
        values = aline.split('\t')
        values.remove('\n') # why?
        table.append(values)
    row_count = len(table)
    row0length = len(table[0])
    print_counter = 4
    for column_index in range(row0length):
        column_total = 0
        for row_index in range(row_count):
            number = float(table[row_index][column_index])
            column_total = column_total + number
        column_average = column_total/row_count
        print column_average
        if print_counter == 4:
            file_write.write(str(column_average)+'\n')
            print_counter = 0
        print_counter +=1
file_write.write('\n')

Быстро становится очевидным, что (1) вы вычисляете средние значения столбцов (2), обфускация заставляла некоторых других думать, что вы вычисляете средние значения в строке.

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

Вот переработанная версия кода внешнего цикла:

for afile in files:
    for row_count, aline in enumerate(afile, start=1):
        values = aline.split('\t')
        values.remove('\n') # why?
        fvalues = map(float, values)
        if row_count == 1:
            row0length = len(fvalues)
            column_index_range = range(row0length)
            column_totals = fvalues
        else:
            assert len(fvalues) == row0length
            for column_index in column_index_range:
                column_totals[column_index] += fvalues[column_index]
    print_counter = 4
    for column_index in column_index_range:
        column_average = column_totals[column_index] / row_count
        print column_average
        if print_counter == 4:
            file_write.write(str(column_average)+'\n')
            print_counter = 0
        print_counter +=1