2017-03-21 5 views
0

Ich schrieb ein einfaches Code-Snippet, um eine Textdatei zu verarbeiten, die eine Phrase pro Zeile mit PoS-markierten Wörtern enthält (zB I/Nomen am/Verb) und ich möchte das Wort extrahieren die Tags getrennt:Speicherleck Python, Listen innerhalb der for Schleife

splitted_sentences = [] 
splitted_pos = [] 

with open("my_path", "r") as tagged_sentences: 
    for sentence in tagged_sentences: 
     curr_sentence = [] 
     curr_pos = [] 
     for tag in sentence.strip().split(" "): 
      splitted_tag = tag.split("/") 
      word = splitted_tag[0] 
      pos = splitted_tag[1] 
      curr_sentence.append(word) 
      curr_pos.append(pos) 
     splitted_sentences.append(curr_sentence) 
     splitted_pos.append(curr_pos) 

der Code funktioniert wie erwartet, aber jedoch Speicher RAM Verbrauch nie aufhört zu erhöhen, während die Schleife über erwartete Ausführung ist gut (Textdatei ist ~ 100 MB und RAM erreicht einen Spitzenverbrauch von 5 GB). Ich habe versucht, einige Speicher-Profiling-Tools zu verwenden und es sieht so aus, als ob ich Tausende von Listenreferenzen erstellen würde (wahrscheinlich curr_sentence- und curr_pos-Listen). Was ist der richtige Weg, um dieses Problem zu lösen, ohne in Speicherlecks zu geraten?

+0

Führen Sie es mit einer sehr kleinen Datei (z. B. 3 Sätze). Verwenden Sie den Debugger, um durch jede Zeile zu gehen und den Inhalt der Variablen zu betrachten. Verwenden Sie eine echte IDE wie PyCharm. –

+0

Sie können 'enumerate (tagged_sentences)' überprüfen, um zu verstehen, wie schnell der Speicher über Ihre Zeilen wächst. – Roelant

+0

Ist das alles der Code? Dieser Teil scheint korrekt zu sein und sollte kein solches Problem erzeugen - aber ist Ihre Textdatei auch gut geformt? Große Teile ohne "/" oder "" könnten dieses Snippet ebenfalls stören. – jsbueno

Antwort

2

splitted_sentences ist eine Liste von Strings. Der Speicheraufwand für Listen beträgt ~ 70 Bytes und ~ 40 Bytes für Zeichenfolgen. Angenommen, durchschnittliche Wort/POS ist 5 Bytes und durchschnittliche Satz ist 10 Wort/POS-Paare, 100 MB Datei ist 1M Sätze * 10 Wörter * 1 Zeichenfolge = (1M * 70) * (10 * 40) = 28 GB Speicher, wenn alle Zeichenfolgen eindeutig waren . Anscheinend sind viele von ihnen nicht, aber dieser Speicherverbrauch könnte ohne Speicherverluste erklärt werden.

Mein Ansatz für dieses Problem wäre die sequentielle Verarbeitung. Ich bezweifle, dass Sie wirklich alle diese Daten gleichzeitig im Speicher benötigen. Ersetzen der Hauptschleife mit einem Generator könnte ein Spiel-Wechsler sein:

def sentence_gen(fname): 
    for sentence in open(fname, 'r'): 
     yield [pair.split("/", 1) for pair in sentence.strip().split()] 
0

Verschieben curr_sentence und curr_pos außerhalb des for-Schleife. Dann können Sie löschen, anstatt neue zu erstellen. Meine Vermutung ist, dass aus irgendeinem Grund die Listen curr_sentence und curr_pos am Ende der for-Schleife nicht gelöscht werden.

Wenn Sie diese Listen außerhalb der for-Schleife verschieben, werden bei jeder Iteration keine neuen Listen erstellt.

+0

Marats Antwort sieht besser aus als meine. :) – Ski