2009-08-19 30 views
16

Estoy colocando alrededor de 4 millones de claves diferentes en un diccionario de Python. La creación de este diccionario dura unos 15 minutos y consume aproximadamente 4 GB de memoria en mi máquina. Una vez que el diccionario está completamente creado, consultar el diccionario es rápido.¿Cómo establecer el tamaño inicial de un diccionario en Python?

Sospecho que la creación de diccionarios consume tantos recursos, ya que el diccionario a menudo se renueva (ya que crece enormemente). ¿Es posible crear un diccionario en Python con algún tamaño inicial o número de segmento?

Mi diccionario apunta de un número a un objeto.

class MyObject(object): 
    def __init__(self): 
    # some fields... 

d = {} 
d[i] = MyObject() # 4M times on different key... 
+0

Muy similar a http://stackoverflow.com/questions/311775/python-create-a-list-dict-with-initial-capacity –

+0

¿Puede decirnos la fuente/formato de sus claves, para que podamos mejorar el awsers? –

+0

la clave es un número – tkokoszka

Respuesta

24

Con problemas de rendimiento, siempre es mejor medir. Aquí están algunos tiempos:

d = {} 
for i in xrange(4000000): 
    d[i] = None 
# 722ms 

d = dict(itertools.izip(xrange(4000000), itertools.repeat(None))) 
# 634ms 

dict.fromkeys(xrange(4000000)) 
# 558ms 

s = set(xrange(4000000)) 
dict.fromkeys(s) 
# Not including set construction 353ms 

La última opción no hace ningún cambio de tamaño, simplemente copia el hash del conjunto e incrementa referencias. Como puede ver, el cambio de tamaño no le toma mucho tiempo. Probablemente tu creación de objeto sea lenta.

+0

No importa cómo inicialice el diccionario, llenarlo con datos siempre lleva mucho tiempo. Parece que de hecho todo el tiempo se gasta en la creación de objetos. ¡Gracias! – tkokoszka

4

Usted puede tratar de separar hash llave del contenido de relleno con dict.fromkeys classmethod. Creará un dict de un tamaño conocido con todos los valores predeterminados a None o un valor de su elección. Después de eso, podría iterar sobre él para llenarlo con los valores. Te ayudará a sincronizar el hash real de todas las teclas. Sin embargo, no estoy seguro de si podría aumentar significativamente la velocidad.

2

Si sus datos deben/pueden ser almacenados en el disco tal vez puede almacenar sus datos en un BSDDB database o utilizar Cpickle para cargar/guardar su dictionnary

5

Si sabes C, puede echar un vistazo a dictobject.c y the Notes on Optimizing Dictionaries . Allí verá el parámetro PyDict_MINSIZE:

PyDict_MINSIZE. Actualmente establecido en 8.

Este parámetro se define en dictobject.h. Entonces podría cambiarlo al compilar Python, pero esto probablemente sea una mala idea.

8

me trataron:

a = dict.fromkeys((range(4000000))) 

crea un diccionario con 4 000 000 entradas en unos 3 segundos. Después de eso, establecer valores es realmente rápido. Así que supongo que dict.fromkey es definitivamente el camino a seguir.

+4

+1 por mencionar dict.fromkeys(). Sin embargo, al usar range() para especificar claves, significa que termina con un dict de claves secuenciales. Si eso es lo que se requiere, ¿por qué no solo usar una lista?a = [Ninguno] * 4000000 –

+1

No fue una solución directa, solo una demostración de que se podían usar las teclas para pregenerar el dict en un tiempo muy ordenado. –

+1

En línea con el punto que plantea @ShawnChin, ¿qué pasa si no quieres los números 1 ... 4M como claves? O, en términos más generales, ¿qué pasa si no conoce sus llaves por adelantado, pero simplemente sabe que están en millones? – posdef

1

¿Inicializa todas las claves con instancias nuevas "vacías" del mismo tipo? ¿No es posible escribir un valor predeterminado o algo que creará el objeto cuando se acceda?

Cuestiones relacionadas