¿Cómo puedo acelerar la eliminación de objetos grandes si tengo suficiente memoria RAM?

Me toma hasta una hora leer una estructura de datos de un gráfico de NetworkX de 1 gigabyte usando cPickle (su 1-GB cuando se almacena en el disco como un archivo binario).

Tenga en cuenta que el archivo se carga rápidamente en la memoria. En otras palabras, si corro:

import cPickle as pickle f = open("bigNetworkXGraph.pickle","rb") binary_data = f.read() # This part doesn't take long graph = pickle.loads(binary_data) # This takes ages 

¿Cómo puedo acelerar esta última operación?

Tenga en cuenta que he intentado capturar los datos utilizando ambos protocolos binarios (1 y 2), y no parece hacer mucha diferencia en qué protocolo utilizo. También tenga en cuenta que aunque estoy usando la función anterior “cargas” (que significa “cadena de carga”), está cargando datos binarios, no datos ASCII.

Tengo 128 GB de RAM en el sistema que estoy usando, así que espero que alguien me diga cómo boost un búfer de lectura enterrado en la implementación de pickle.

Probablemente esté sujeto a la sobrecarga de creación / asignación de objetos de Python, no a la eliminación en sí misma. Si es así, hay poco que puedas hacer para acelerar esto, excepto que no se creen todos los objetos. ¿Necesitas toda la estructura a la vez? De lo contrario, podría usar una población perezosa de la estructura de datos (por ejemplo: representar partes de la estructura mediante cadenas encurtidas, luego deshacerlas solo cuando se accede a ellas).

Tuve un gran éxito al leer una estructura de datos igraph de ~ 750 MB (un archivo binario pickle) utilizando cPickle. Esto se logró simplemente envolviendo la llamada de carga de salmuera como se menciona aquí

Un fragmento de ejemplo en tu caso sería algo como:

 import cPickle as pickle import gc f = open("bigNetworkXGraph.pickle", "rb") # disable garbage collector gc.disable() graph = pickle.load(f) # enable garbage collector again gc.enable() f.close() 

Esta definitivamente no es la forma más adecuada de hacerlo, sin embargo, reduce el tiempo requerido drásticamente.
(Para mí, se redujo de 843.04s a 41.28s, alrededor de 20x)

¿Por qué no intenta calcular sus datos y almacenarlos en la RAM utilizando memcached (por ejemplo)? Sí, tiene algunas limitaciones, pero como esto señala, calcular es mucho más rápido (20 a 30 veces) que el decapado.

Por supuesto, también debe pasar todo el tiempo optimizando su estructura de datos para minimizar la cantidad y complejidad de los datos que desea almacenar.

Esto es ridículo.

Tengo un enorme diccionario de ~ 150MB ( collections.Counter Encuentro en realidad) que estaba leyendo y escribiendo usando cPickle en formato binario.

Escribiéndolo tardó unos 3 min.
Dejé de leerlo en la marca de 16 minutos, con mi memoria RAM completamente ahogada.

Ahora estoy usando mariscal, y se necesita: escribir: ~ 3s
leer: ~ 5s

Hurgué un poco, y encontré este artículo .
Supongo que nunca he mirado la fuente de pickle, pero ¿construye una máquina virtual completa para reconstruir el diccionario?
Debería haber una nota sobre el rendimiento en objetos muy grandes en la documentación IMHO.

También estoy tratando de acelerar la carga / almacenamiento de los gráficos de networkx. Estoy usando el método adjacency_graph para convertir el gráfico en algo que se puede serializar, vea por ejemplo este código:

 from networkx.generators import fast_gnp_random_graph from networkx.readwrite import json_graph G = fast_gnp_random_graph(4000, 0.7) with open('/tmp/graph.pickle', 'wb+') as f: data = json_graph.adjacency_data(G) pickle.dump(data, f) with open('/tmp/graph.pickle', 'rb') as f: d = pickle.load(f) H = json_graph.adjacency_graph(d) 

Sin embargo, este método de conversión adjacency_graph es bastante lento, por lo que el tiempo ganado en el decapado probablemente se pierde en la conversión.

Así que esto en realidad no acelera las cosas, bummer. Ejecutar este código da los siguientes tiempos:

 N=1000 0.666s ~ generating 0.790s ~ converting 0.237s ~ storing 0.295s ~ loading 1.152s ~ converting N=2000 2.761s ~ generating 3.282s ~ converting 1.068s ~ storing 1.105s ~ loading 4.941s ~ converting N=3000 6.377s ~ generating 7.644s ~ converting 2.464s ~ storing 2.393s ~ loading 12.219s ~ converting N=4000 12.458s ~ generating 19.025s ~ converting 8.825s ~ storing 8.921s ~ loading 27.601s ~ converting 

Este crecimiento exponencial probablemente se deba a que la gráfica obtiene exponencialmente más bordes. Aquí hay una prueba esencial, en caso de que quiera probarlo usted mismo.

https://gist.github.com/wires/5918834712a64297d7d1

Tal vez lo mejor que puedes hacer es dividir el big data en el objeto más pequeño más pequeño, digamos, más de 50MB, para que pueda almacenarse en el ram, y recombinarlo.

Afaik no hay manera de dividir automáticamente los datos a través del módulo pickle, por lo que tiene que hacerlo usted mismo.

De todos modos, otra forma (que es bastante más difícil) es usar alguna base de datos NoSQL como MongoDB para almacenar sus datos …

En general, he encontrado que, si es posible, cuando se guardan objetos grandes en un disco en Python, es mucho más eficiente usar un número de ndarrays o matrices scipy.sparse.

Por lo tanto, para gráficos enormes como el del ejemplo, podría convertir el gráfico en una matriz dispersa escasa (networkx tiene una función que hace esto, y no es difícil escribir una), y luego guardar esa matriz dispersa en formato binario.

¿Por qué no usas pickle.load ?

 f = open('fname', 'rb') graph = pickle.load(f)