Diccionario basado en disco de Python
database dictionary (9)
Estaba ejecutando un código de programación dinámico (tratando de usar la fuerza bruta para refutar la conjetura de Collatz = P) y estaba usando un dict para almacenar las longitudes de las cadenas que ya había calculado. Obviamente, se quedó sin memoria en algún momento. ¿Hay alguna manera fácil de usar alguna variante de un dict
que dict
partes de sí mismo en el disco cuando se quede sin espacio? Obviamente, será más lento que un dict en memoria, y probablemente terminará consumiendo mi espacio en el disco duro, pero esto podría aplicarse a otros problemas que no son tan inútiles.
Me di cuenta de que un diccionario basado en disco es más o menos una base de datos, así que implementé manualmente uno usando sqlite3, pero no lo hice de manera inteligente y tuve que buscar cada elemento en el DB uno a la vez ... era aproximadamente 300 veces más lento.
¿Es la forma más inteligente de crear solo mi propio conjunto de dictados, mantener solo uno en la memoria a la vez y distribuirlos de una manera eficiente?
Hash-on-disk generalmente se trata con Berkeley DB o algo similar; hay varias opciones en la documentación de Python Data Persistence . Puede afrontarlo con un caché en memoria, pero probaría primero el rendimiento nativo; con el almacenamiento en caché del sistema operativo en su lugar, podría salir más o menos igual.
Con un poco de pensamiento, parece que podría obtener el módulo de estante para hacer lo que quiera.
Debería traer más de un elemento a la vez si hay alguna heurística para saber cuáles son los artículos más probables que se recuperarán a continuación, y no olvide los índices como menciona Charles.
La última vez que me enfrenté a un problema como este, reescribí para usar SQLite en lugar de un dict y tuve un aumento de rendimiento masivo. Ese aumento en el rendimiento se debió, al menos parcialmente, a las capacidades de indexación de la base de datos; dependiendo de tus algoritmos, YMMV.
Un contenedor delgado que realiza consultas SQLite en __getitem__
y __setitem__
no es mucho código para escribir.
El módulo de estantería puede hacerlo; de todos modos, debería ser simple de probar. En lugar de:
self.lengths = {}
hacer:
import shelve
self.lengths = shelve.open(''lengths.shelf'')
La única pega es que las llaves de los estantes deben ser cuerdas, por lo que tendrás que reemplazar
self.lengths[indx]
con
self.lengths[str(indx)]
(Supongo que sus claves son enteros, según su comentario a la publicación de Charles Duffy)
No hay memoria caché incorporada en la memoria, pero su sistema operativo puede hacer eso por usted de todos modos.
[en realidad, eso no es del todo cierto: puede pasar el argumento ''writeback = True'' en la creación. La intención de esto es asegurarse de que las listas de almacenamiento y otras cosas mutables en el estante funcionen correctamente. Pero un efecto secundario es que todo el diccionario está almacenado en la memoria. Como esto le causó problemas, probablemente no sea una buena idea :-)]
No lo intenté todavía, pero Hamster DB es prometedor y tiene una interfaz de Python.
También vale la pena echarle un vistazo al módulo shove de terceros. Es muy similar a shelve porque es un objeto simple parecido a un dictado, sin embargo, puede almacenarse en varios backends (como archivos, SVN y S3), proporciona compresión opcional e incluso es seguro para los hilos. Es un módulo muy útil
from shove import Shove
mem_store = Shove()
file_store = Shove(''file://mystore'')
file_store[''key''] = value
Leí que crees que shelve es demasiado lento e intentaste hackear tu propio dict usando sqlite.
Otro hizo esto también:
http://sebsauvage.net/python/snyppets/index.html#dbdict
Parece bastante eficiente (y sebsauvage es un codificador bastante bueno). ¿Tal vez podrías intentarlo?
lea la respuesta de GvR para esta pregunta;) Ordene un millón de enteros de 32 bits en 2MB de RAM usando Python