2013-07-20 11 views
8

Ho lavorato su questo per alcune settimane e ho letto molte domande sulla perdita di memoria di Python ma non riesco a capirlo.Python gets Killed (probabilmente perdita di memoria)

Ho un file che contiene circa 7 milioni di righe. Per ogni linea, ho bisogno di creare un dizionario. Quindi questo è un elenco di dizionario che assomiglia:

[{'a': 2, 'b':1}{'a':1, 'b':2, 'c':1}] 

Quello che sto facendo è ...

list = [] 
for line in file.readlines(): 
    terms = line.split(" ") 
    dict = {} 
    for term in terms: 
     if term in dict: 
      dict[term] = dict[term] + 1 
     else: 
      dict[term] = 1 
    list.append(dict.copy()) 
    dict.clear() 
file.close() 

Il problema è che quando faccio funzionare questo sempre viene ucciso attorno alla linea 6000000o. Inizialmente stavo semplicemente facendo dict = {} ma l'ho cambiato così faccio dict.clear() dopo aver letto post simili, ma non ha migliorato nulla. Conosco alcuni post menzionati su riferimenti circolari e ho esaminato il mio codice ma non pensavo di avere quel problema.

Dubito che la memorizzazione di 7 milioni di dizionari in un elenco non possa essere gestita in Python? Gradirei qualche consiglio su come posso gestire tutto senza essere ucciso.

(la versione è 2.7.4)

+2

Cosa stai cercando di ottenere qui? –

+0

@ThomasOrozco Ho modificato la mia domanda un po ', ma quello che sto cercando di fare è archiviare il termine dizionario di conteggio per ogni riga – kabichan

+2

Hai provato a sostituire _for linea in file.readlines(): _ di _per riga nel file: _ ? – uselpa

risposta

8

Prova:

from collections import Counter 
with open('input') as fin: 
    term_counts = [Counter(line.split()) for line in fin] 

Credo che questo è ciò che si sta cercando di raggiungere con il vostro codice.

Questo evita la .readlines() caricamento del file in memoria prima, utilizza Counter a fare il conteggio e costruisce la lista in una sola volta, senza cazzeggio tranciatura/assegnare/compensazione dizionari/aggiungendo alle liste ...

+0

Ho provato e si è ancora ammazzato .. l'unica cosa che ho fatto in modo diverso dal tuo è che ho una variabile per il nome del file, quindi ho fatto 'con open (filename) come fin:' e il resto è lo stesso. – kabichan

+0

@kabichan Questo è semplice come si ottiene per quello che vuoi - sembra che tu possa dover archiviare i dati su disco/in un DB –

+0

Se questo non è perché non sto facendo quello che posso fare, allora posso andare avanti e prova qualcos'altro. Accetterò la tua come risposta perché sembra che questo risolva problemi simili. Grazie mille per il consiglio. – kabichan

1

C'è in nessun modo si potrebbe avere una perdita di memoria con uno snippet di codice così semplice, perché Python usa almeno metà della garbage collection decente. Un potenziale problema è che potresti aver esaurito la memoria (quindi evita assolutamente .readlines per i principianti; usa invece "per line in my_file"); anche un dizionario usa effettivamente un bel po 'di memoria per vari motivi - uno è che un dizionario usa intenzionalmente una tabella hash considerevolmente più grande dell'attuale attuale serie di chiavi, sia per aiutare a mitigare le collisioni, ma anche per poter aggiungere rapidamente molto di nuove chiavi se necessario, con tempo O (1) ammortizzato per inserimento. Dato che ti stai avvicinando alla fine del tuo file prima che muoia, una cosa che potresti provare è quella di memorizzare il tuo dict finale come una tupla di 2 t-k, dove la prima tupla k contiene le chiavi k che vuoi memorizzare e la seconda k-tupla è il tuo k conta per le chiavi k. Questo dovrebbe risparmiare un po 'di memoria, a spese che, al fine di fare un look-up di my_key in uno dei tuoi 2-tuple T avrete bisogno di fare qualcosa di simile:

match_idx = [i for i in xrange(len(T[0])) if T[0][i] == my_key] 
if len(match_idx) == 0: 
    # no match, do whatever 
else: #match 
    count = T[1][match_idx[0]] 
    # now do whatever with count 

Il tempo di esecuzione per un look up sarà lineare nel numero di chiavi da cercare, invece di tempo costante (anche se si noti che l'hashing per fare una ricerca nel dizionario non è un'operazione banale, quindi la costante è più grande di una costante tipica per un'operazione più semplice). Se hai archiviato le tue chiavi in ​​ordine, puoi usare la ricerca binaria per trovare rapidamente la tua chiave, ma questo richiederebbe più codice, e presumo che tu stia usando python in parte perché tende a fornire un codice breve. Tuttavia, se stai già creando con successo 6 milioni di tuoi dizionari, in media i tuoi 7 milioni di dizionari non devono avere molte chiavi al loro interno. Quindi, se vuoi veramente usare python per il tuo set di dati, questo può essere uno dei pochi modi per andare a meno che tu non abbia una macchina con più memoria.