¿Por qué los pepinillos comen la memoria?

Intento lidiar con la escritura de una gran cantidad de datos encurtidos en un disco por partes pequeñas. Aquí está el código de ejemplo:

from cPickle import * from gc import collect PATH = r'd:\test.dat' @profile def func(item): for e in item: f = open(PATH, 'a', 0) f.write(dumps(e)) f.flush() f.close() del f collect() if __name__ == '__main__': k = [x for x in xrange(9999)] func(k) 

Abra () y cierre () colocado dentro del bucle para excluir posibles causas de acumulación de datos en la memoria.

Para ilustrar el problema, adjunto los resultados de los perfiles de memoria obtenidos con Python 3d party module memory_profiler :

  Line # Mem usage Increment Line Contents ============================================== 14 @profile 15 9.02 MB 0.00 MB def func(item): 16 9.02 MB 0.00 MB path= r'd:\test.dat' 17 18 10.88 MB 1.86 MB for e in item: 19 10.88 MB 0.00 MB f = open(path, 'a', 0) 20 10.88 MB 0.00 MB f.write(dumps(e)) 21 10.88 MB 0.00 MB f.flush() 22 10.88 MB 0.00 MB f.close() 23 10.88 MB 0.00 MB del f 24 collect() 

Durante la ejecución del bucle se produce un crecimiento de uso de memoria extraña. ¿Cómo se puede eliminar? ¿Alguna idea?

Cuando la cantidad de datos de entrada aumenta, el volumen de estos datos adicionales puede crecer hasta un tamaño mucho mayor que la entrada (actualización: en la tarea real obtengo 300 + Mb)

Y una pregunta más amplia: ¿qué formas existen para trabajar correctamente con grandes cantidades de datos de IO en Python?

upd: reescribí el código dejando solo el cuerpo del bucle para ver cuándo ocurre el crecimiento específicamente, y aquí están los resultados:

 Line # Mem usage Increment Line Contents ============================================== 14 @profile 15 9.00 MB 0.00 MB def func(item): 16 9.00 MB 0.00 MB path= r'd:\test.dat' 17 18 #for e in item: 19 9.02 MB 0.02 MB f = open(path, 'a', 0) 20 9.23 MB 0.21 MB d = dumps(item) 21 9.23 MB 0.00 MB f.write(d) 22 9.23 MB 0.00 MB f.flush() 23 9.23 MB 0.00 MB f.close() 24 9.23 MB 0.00 MB del f 25 9.23 MB 0.00 MB collect() 

Parece que los vertederos () se comen la memoria. (Mientras que en realidad pensé que sería escribir ())

Pickle consume una gran cantidad de RAM, consulte las explicaciones aquí: http://www.shocksolution.com/2010/01/storing-large-numpy-arrays-on-disk-python-pickle-vs-hdf5adsf/

¿Por qué Pickle consume mucha más memoria? La razón es que HDF es un canal de datos binarios, mientras que Pickle es un protocolo de serialización de objetos. Pickle en realidad consiste en una simple máquina virtual (VM) que traduce un objeto en una serie de códigos de operación y los escribe en el disco. Para desentrañar algo, la máquina virtual lee e interpreta los códigos de operación y reconstruye un objeto. La desventaja de este enfoque es que la VM tiene que construir una copia completa del objeto en la memoria antes de escribirla en el disco.

Pickle es ideal para casos de uso pequeños o pruebas porque en la mayoría de los casos el consumo de memoria no importa mucho.

Para trabajos intensivos en los que tiene que volcar y cargar muchos archivos y / o archivos grandes, debería considerar usar otra forma de almacenar sus datos (por ejemplo, hdf, escribió sus propios métodos de serialización / deserialización para su objeto, …)