[pyar] ¿cómo guardar variables GRANDES en archivos?

Iván Raskovsky raskovsky en gmail.com
Mar Ene 18 05:30:26 ART 2011


2011/1/18 Claudio Freire <klaussfreire en gmail.com>:
> Lo que describís parece indicar un comportamiento cuadrático en cPickle.

Claudio, me sacaste el post de las manos! Llegué a conclusiones
parecidas hace un rato. x)

> Tengo entendido que unladen-swallow optimizó muchísimo cPickle, y que muchas
> de las optimizaciones las mergearon en Python 3. Así que podrías probar con
> python3.

Sí, efectivamente el problema se alivió muchísimo en Python 3
(funciona bien), pero lamentablemente las bibliotecas que estoy usando
todavía no fueron portadas (nltk).

> Más allá de eso, el comportamiento cuadrático molesta cuando tratás con
> estructuras grandes. Para esquivar esto, te recomiendo evitar estructuras
> grandes.
>
> Tu archivo puede consistir de varios objetos pickleados en secuencia. Por
> ejemplo, en vez de un pickle con todos los documentos, podés picklear
> documentos uno atrás de otro, y hacer cPickle.load() hasta que tengas un
> EOF, cargando documento por documento en vez de todos de una.
>
> try:
>    while True:
>        docs.append(cPickle.load(f))
> except EOFError:
>    pass
>
> Si hay documentos muy grandes, podés partir también cada documento en
> oraciones:
>
> try:
>    while True:
>        oraciones = cPickle.load(f)
>        doc = [ cPickle.load(f) for x in xrange(oraciones) ]
>        docs.append(doc)
> except EOFError:
>    pass
>
> Bue, eso es para cargar, para grabar es algo parecido.
>
> Etc.
>
> Eso debería aliviarte tu problema de orden cuadrático en el pickleado, sin
> cambiar la representación en memoria de los datos que querés manejar.

Sí, no lo probé, pero al ser 37 mil documentos pequeños también es un
poco molesto tener tantos archivos.

> El otro problema que podés tener es que la representación que elegiste sea
> demasiado ineficiente.
>
> Cada palabra es una tupla de 2, más la cadena, que asumiendo un promedio de
> 5 letras por palabra sería algo así como 74 bytes.
>
> Asimismo, cada oración es una lista de, asumamos, promedio 25 palabras, o
> sea 16 + (8 + 74) * 25 = 2066 bytes.
>
> Asimismo, cada documento es una lista de oraciones, Ni idea cuántas, pero...
> sabiendo que cada oración ocupa 2066 bytes en memoria y representa 150
> letras de texto, si tu archivo de texto ocupa 200MB, es esperable que en
> memoria todo te ocupe 2754MB (regla de tres). Eso son 2.7G. Muy ineficiente.
>
> Algunas cosas que podés hacer para alivianar el uso de memoria es, por
> ejemplo, aprovechar el hecho de que se van a repetir mucho algunos pares
> (palabra, pos), y unificar. Por ejemplo, si aparece ('memoria', 'od') 1000
> veces, no necesitás 1000 tuplas. Usando un diccionario, podés "canonizar" la
> palabra:
>
> palabras = {}
>
> ...
> palabra = palabras.setdefault(palabra,palabra)
>
> Claro que si no hay mucho reuso, el diccionario puede pesarte más de lo que
> te ahorra.

Interesante, pero no veo bien como utilizarlo ya que cada "palabra"
puede tener diferentes usos en cada aparición.

> En síntesis... tenés un problema de ineficiencia inherente a lo que querés
> hacer, diría yo, más que nada. Probablemente deberías evitar tener todo en
> memoria.

Es fue mi solución! Lo que terminé haciendo es leer un documento,
procesarlo y luego guardarlo, uno detrás de otro en un archivo. Más
adelante lo que voy a hacer va a ser bufferear la lectura del archivo
por un lado para bajar la cantidad de lecturas a disco y paralelizarlo
y utilizar MPI I/O para que cada proceso pueda escribir
independientemente de los otros y en orden. Vamos a ver cuánto
overhead trae.

Muchas gracias a todos!
    Iván



More information about the pyar mailing list