2015-07-15 5 views
7

L'ho sperimentato in altre lingue. Ora ho lo stesso problema in Python. Ho un dizionario che ha molte azioni CRUD. Si potrebbe presumere che l'eliminazione di elementi da un dizionario dovrebbe ridurre l'impronta di memoria di esso. Non è il caso. Una volta che un dizionario cresce di dimensioni (di solito raddoppia), non rilascia mai (?) Le memorie allocate. Ho eseguito questo esperimento:Come forzare il dizionario Python a ridursi?

import random 
import sys 
import uuid 

a= {} 
for i in range(0, 100000): 
    a[uuid.uuid4()] = uuid.uuid4() 
    if i % 1000 == 0: 
     print sys.getsizeof(a) 

for i in range(0, 100000): 
    e = random.choice(a.keys()) 
    del a[e] 
    if i % 1000 == 0: 
     print sys.getsizeof(a) 

print len(a) 

L'ultima riga del primo ciclo è 6291736. L'ultima riga del secondo ciclo è anche 6291736. E la dimensione del dizionario è 0.

Quindi, come affrontare questo problema? C'è un modo per forzare il rilascio della memoria?

PS: non ho davvero bisogno di fare random - Ho giocato con il range del secondo ciclo.

+0

Si potrebbe provare a creare un nuovo dizionario con il contenuto di quello vecchio e rimuovere il riferimento a quello vecchio. – iobender

+0

A che punto? In orario? Come posso bloccare le scritture? – Schultz9999

+0

I moduli 'threading',' multiprocessing' di Python e 'asyncio' * all * forniscono primitive di sincronizzazione quasi identiche come' Lock'. Vorrei iniziare a cercare nella documentazione del modulo applicabile. – brenns10

risposta

2

Il modo per eseguire questo "rehashing" in modo che utilizzi meno memoria è creare un nuovo dizionario e copiare il contenuto.

Il Python dizionario implementazione è spiegato molto bene in questo video:

https://youtu.be/C4Kc8xzcA68

C'è un atendee porre questa stessa domanda (https://youtu.be/C4Kc8xzcA68?t=1593), e la risposta data da chi parla è:

Le riduzioni sono calcolate solo al momento dell'inserimento; man mano che un dizionario si restringe, guadagna un sacco di voci fittizie e, man mano che si ricarica, si inizia a riutilizzare quelle per memorizzare le chiavi. [...] è necessario copiare le chiavi ei valori fuori ad un nuovo dizionario

+1

Le risposte di solo collegamento non sono buone risposte. –

+1

Non posso semplicemente fermare tutto - le richieste arrivano in modo asincrono. Sicuramente il modello asincrono di Python è storto, ma non c'è alcuna garanzia che mentre sposto i dati da un dizionario all'altro, non ci saranno cambiamenti in quello di origine. – Schultz9999

+1

Sembra molto simile alla raccolta dei rifiuti stop-the-world, e allo stesso modo è possibile utilizzare un blocco in modo che le richieste asincrone attenda che il ditt viene ricreato. Ulteriori informazioni su Lock: https://docs.python.org/2/library/threading.html – franciscod

1

In realtà un dizionario può restringersi su di ridimensionamento, ma il ridimensionamento avviene solo su un inserto chiave non la rimozione. Ecco un commento da parte del CPython source per dictresize:

Ristrutturare la tabella assegnando una nuova tabella e reinserire nuovamente tutti articoli. Quando le voci sono state eliminate, la nuova tabella potrebbe essere effettivamente più piccola di quella precedente.

Tra l'altro, dal momento che l'altra risposta cita Brandon Rhodes talk il dizionario a PyCon 2010 e la citazione sembra essere in contrasto con quanto sopra (che è stato lì per anni), ho pensato di includere il pieno citazione, con la parte mancante in grassetto.

Le riduzioni vengono calcolate solo al momento dell'inserimento. Come un dizionario si riduce, guadagna un sacco di voci fittizie e come si ricarica, sarà solo iniziare riutilizzare quelli per memorizzare le chiavi. Non verrà ridimensionato finché non si è riusciti a rendere nuovamente i due terzi pieni due volte superiori alle dimensioni maggiori di . Quindi lo non viene ridimensionato quando si eliminano le chiavi. Devi fare un inserto per ottenere per capire che deve ridursi.

Così dice che l'operazione di ridimensionamento può "capire [il dizionario] deve ridursi". Ma ciò accade solo sull'inserto.Apparentemente quando si copia su tutte le chiavi durante il ridimensionamento, le chiavi fittizie possono essere rimosse, riducendo le dimensioni dell'array di supporto.

Non è chiaro, tuttavia, come farlo accadere, ed è per questo che Rhodes dice di copiare tutto su un nuovo dizionario.