python memory

python - Límite de memoria superior?



memory (5)

Estás leyendo todo el archivo en la memoria ( line = u.readlines() ) que, por supuesto, fallará si el archivo es demasiado grande (y dices que algunos son de hasta 20 GB), así que ese es tu problema allí mismo.

Mejor iterar sobre cada línea:

for current_line in u: do_something_with(current_line)

es el enfoque recomendado

Más adelante en el guión, estás haciendo cosas muy extrañas, como contar primero todos los elementos de una lista y luego construir un ciclo for ese conteo. ¿Por qué no iterar sobre la lista directamente? ¿Cuál es el propósito de tu script? Tengo la impresión de que esto podría hacerse mucho más fácil.

Esta es una de las ventajas de los lenguajes de alto nivel como Python (a diferencia de C, donde usted mismo tiene que hacer estas tareas de limpieza): Permita que Python maneje la iteración por usted, y solo recopile en memoria lo que realmente necesita tener en memoria en cualquier momento dado.

Además, como parece que estás procesando archivos TSV (valores separados por tabulador), deberías echarle un vistazo al módulo csv que manejará toda la división, eliminación de /n s, etc. para ti.

¿Hay un límite en la memoria para Python? He estado usando un script de python para calcular los valores promedio de un archivo que tiene un mínimo de 150 mb de tamaño.

Dependiendo del tamaño del archivo, a veces encuentro un MemoryError .

¿Se puede asignar más memoria a la python para que no encuentre el error?

EDITAR: Código ahora debajo

NOTA: Los tamaños de archivo pueden variar mucho (hasta 20 GB), el tamaño mínimo del archivo es 150 MB.

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'')


No solo está leyendo el total de cada archivo en la memoria, sino que también replica laboriosamente la información en una tabla llamada list_of_lines .

Usted tiene un problema secundario: sus elecciones de nombres de variables ofuscan severamente lo que está haciendo.

Aquí está el guión reescrito con la destreza readlines () eliminada y con nombres significativos:

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'')

Se vuelve rápidamente evidente que (1) está calculando promedios de columna (2) la ofuscación llevó a otros a pensar que estaba calculando promedios de fila.

A medida que calcula los promedios de las columnas, no se requiere ninguna salida hasta el final de cada archivo, y la cantidad de memoria extra realmente requerida es proporcional al número de columnas.

Aquí hay una versión revisada del código del bucle externo:

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


No, no hay un límite específico de Python en el uso de la memoria de una aplicación Python. Trabajo regularmente con aplicaciones de Python que pueden usar varios gigabytes de memoria. Lo más probable es que su script realmente use más memoria que la disponible en la máquina en la que se está ejecutando.

En ese caso, la solución es volver a escribir la secuencia de comandos para que sea más eficiente en cuanto a la memoria o para agregar más memoria física si la secuencia de comandos ya está optimizada para minimizar el uso de la memoria.

Editar:

Su secuencia de comandos lee todo el contenido de sus archivos en la memoria a la vez ( line = u.readlines() ). Dado que está procesando archivos de hasta 20 GB de tamaño, obtendrá errores de memoria con ese enfoque a menos que tenga una gran cantidad de memoria en su máquina.

Un mejor enfoque sería leer los archivos una línea a la vez:

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


Python puede usar toda la memoria disponible para su entorno. Mi simple "prueba de memoria" se bloquea en ActiveState Python 2.6 después de usar about

1959167 [MiB]

En jython 2.5 se bloquea antes:

239000 [MiB]

probablemente pueda configurar Jython para usar más memoria (usa límites de JVM)

Aplicación de prueba:

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))

En su aplicación, lee todo el archivo de una vez. Para archivos tan grandes, debe leer la línea por línea.


(Esta es mi tercera respuesta porque entendí mal lo que tu código estaba haciendo en mi original, y luego cometí un pequeño pero crucial error en mi segundo, ojalá sea un encanto de tres.

Ediciones : Dado que esta parece ser una respuesta popular, hice algunas modificaciones para mejorar su implementación a lo largo de los años, la mayoría no demasiado importante. Esto es así si la gente lo utiliza como plantilla, proporcionará una base aún mejor.

Como han señalado otros, su problema con MemoryError es más probable porque está intentando leer todo el contenido de archivos grandes en la memoria y luego, además de eso, duplica la cantidad de memoria necesaria al crear una lista de listas del valores de cadena de cada línea

Los límites de memoria de Python están determinados por la cantidad de memoria física y memoria virtual que su computadora y sistema operativo tienen disponible. Incluso si no lo usa todo y su programa "funciona", usarlo puede ser poco práctico porque lleva demasiado tiempo.

De todos modos, la forma más obvia de evitar eso es procesar cada archivo una sola línea a la vez, lo que significa que debe hacer el procesamiento de forma incremental.

Para lograr esto, se mantiene una lista de totales acumulados para cada uno de los campos. Cuando eso finalice, el valor promedio de cada campo se puede calcular dividiendo el valor total correspondiente por el recuento de líneas totales leídas. Una vez hecho esto, estos promedios se pueden imprimir y algunos escritos en uno de los archivos de salida. También hice un esfuerzo consciente para usar nombres de variables muy descriptivos para tratar de hacerlo comprensible.

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()