Shelve es demasiado lento para los diccionarios grandes, ¿qué puedo hacer para mejorar el rendimiento?

Estoy almacenando una tabla usando python y necesito persistencia.

Esencialmente estoy almacenando la tabla como una cadena de diccionario a números. Y todo se guarda con repisa.

self.DB=shelve.open("%s%sMoleculeLibrary.shelve"%(directory,os.sep),writeback=True) 

Uso el valor de writeback a True ya que el sistema tiende a ser inestable si no lo hago.

Después de los cálculos, el sistema necesita cerrar la base de datos y almacenarla. Ahora la base de datos (la tabla) tiene aproximadamente 540 MB, y está tomando años. El tiempo explotó después de que la mesa creció a unos 500MB. Pero necesito una mesa mucho más grande. De hecho necesito dos de ellos.

Probablemente estoy usando la forma incorrecta de persistencia. ¿Qué puedo hacer para mejorar el rendimiento?

Para almacenar un gran diccionario de pares string : number clave-valor, sugeriría una solución de almacenamiento nativa JSON como MongoDB . Tiene una API maravillosa para Python, Pymongo . MongoDB en sí mismo es liviano e increíblemente rápido, y los objetos json serán nativos de forma nativa en Python. Esto significa que puede usar su clave de string como la identificación del objeto, lo que permite un almacenamiento comprimido y una búsqueda rápida.

Como ejemplo de lo fácil que sería el código, vea lo siguiente:

 d = {'string1' : 1, 'string2' : 2, 'string3' : 3} from pymongo import Connection conn = Connection() db = conn['example-database'] collection = db['example-collection'] for string, num in d.items(): collection.save({'_id' : string, 'value' : num}) # testing newD = {} for obj in collection.find(): newD[obj['_id']] = obj['value'] print newD # output is: {u'string2': 2, u'string3': 3, u'string1': 1} 

Solo deberías volver a convertir de Unicode, lo cual es trivial.

Según mi experiencia, recomendaría el uso de SQLite3 , que viene con Python. Funciona bien con bases de datos más grandes y números clave. Millones de claves y gigabytes de datos no son un problema. Shelve está totalmente perdido en ese punto. Además, tener un proceso db separado no es beneficioso, solo requiere más cambios de contexto. En mis pruebas descubrí que SQLite3 era la opción preferida para usar, cuando se manejaban grandes conjuntos de datos localmente. El funcionamiento del motor de base de datos local como mongo, mysql o postgresql no proporciona ningún valor adicional y también fue más lento.

¿Cuánto más grande? ¿Cuáles son los patrones de acceso? ¿Qué tipo de cómputo necesitas hacer al respecto?

Tenga en cuenta que tendrá algunos límites de rendimiento si no puede mantener la tabla en la memoria sin importar cómo lo haga.

Si lo desea, puede consultar ir a SQLAlchemy o usar directamente algo como bsddb , pero ambos sacrificarán la simplicidad del código. Sin embargo, con SQL puede descargar parte del trabajo a la capa de la base de datos, dependiendo de la carga de trabajo.

Creo que su problema se debe al hecho de que utiliza writeback=True . La documentación dice (el énfasis es mío):

Debido a la semántica de Python, un estante no puede saber cuándo se modifica una entrada de diccionario persistente mutable. De forma predeterminada, los objetos modificados se escriben solo cuando se asignan a la estantería (ver Ejemplo). Si el parámetro de reescritura opcional se establece en Verdadero, todas las entradas a las que se accede también se almacenan en la memoria caché y se escriben de nuevo en sync () y close (); esto puede hacer que sea más fácil mutar las entradas mutables en el diccionario persistente, pero, si se accede a muchas entradas, puede consumir grandes cantidades de memoria para el caché, y puede hacer que la operación de cierre sea muy lenta, ya que todas las entradas a las que se accede se registran ( no hay manera de determinar qué entradas accedidas son mutables, ni cuáles fueron mutadas en realidad).

Podría evitar usar writeback=True y asegurarse de que los datos se escriban solo una vez (debe prestar atención a las modificaciones posteriores que se perderán).

Si crees que esta no es la opción de almacenamiento correcta (es difícil decirlo sin saber cómo están estructurados los datos), sugiero sqlite3, está integrado en python (por lo tanto, muy portátil) y tiene muy buenas prestaciones. Es algo más complicado que una simple tienda de valor-clave.

Vea otras respuestas para alternativas.