2016-04-08 8 views
4

Ich schreibe ein sehr einfaches Skript, das die Anzahl der Vorkommen in einer Datei zählt. Die Dateigröße beträgt ca. 300 MB (15 Millionen Zeilen) und hat 3 Spalten. Da ich die Datei zeilenweise lese, erwarte ich nicht, dass Python viel Speicher verbraucht. Maximum würde etwas über 300Mb sein, um das Zählung Dictionnary zu speichern.Python übermäßigen Speicherverbrauch mit einfachen Skript

Wenn ich jedoch auf Aktivitätsmonitor schaue, gehe die Speicherbelegung über 1,5 GB. Was mache ich falsch ? Wenn es normal ist, könnte das bitte jemand erklären? Dank

import csv 
def get_counts(filepath): 
    with open(filepath,'rb') as csvfile: 
     reader = csv.DictReader(csvfile, fieldnames=['col1','col2','col3'], delimiter=',') 
     counts = {} 
     for row in reader: 

      key1 = int(row['col1']) 
      key2 = int(row['col2']) 

      if (key1, key2) in counts: 
       counts[key1, key2] += 1 
      else: 
       counts[key1, key2] = 1 

    return counts 
+0

Haben Sie die Methode 'csv.reader' versuchen:' data = csv.reader (open (csvfile), delimiter = '') 'und dann' für Zeile in Daten: '? [Quelle] (http://lethain.com/handling-yy-large-csv-and-xml-files-in-python/) – Till

+0

Sie könnten auch 'count [key1, key2] = count.get ((key1 , key2), 0) + 1 'anstelle der 'if else'-Anweisung. – Till

+0

Vielleicht ist es nur ein Problem mit der Einfügung, aber die dritte Zeile ist nicht eingerückt (und daher auch die vierte Zeile), was dazu führt, dass Ihr Skript einen Fehler ausgibt. –

Antwort

2

Ich denke, es ist ganz in Ordnung, dass Python in Ihrem Fall so viel Speicher verwendet. Hier ist ein Test auf meinem Rechner:

Python 2.7.10 (default, Oct 23 2015, 19:19:21) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)] on darwin 
>>> file_size = 300000000 
>>> column_count = 10 
>>> average_string_size = 10 
>>> row_count = file_size/(column_count * average_string_size) 
>>> row_count 
3000000 
>>> import os, psutil, cPickle 
>>> mem1 = psutil.Process(os.getpid()).memory_info().rss 
>>> data = [{column_no: '*' * average_string_size for column_no in xrange(column_count)} for row_no in xrange(row_count)] 
>>> mem2 = psutil.Process(os.getpid()).memory_info().rss 
>>> mem2 - mem1 
4604071936L 
>>> 

So ist die vollständige Liste der 3000000 dict mit 10 Stück mit Strings der Länge 10 ist mehr das 4 GB RAM verwenden.

In Ihrem Fall glaube ich nicht, dass die CSV-Daten den RAM nimmt. Es ist Ihr counts Wörterbuch.

Eine andere Erklärung wäre, dass die dicts, die nacheinander aus der csv-Datei gelesen werden, nicht sofort als Müll gesammelt werden (obwohl ich das nicht bestätige).

Auf jeden Fall verwenden, um ein spezielles Tool, um zu sehen, was das Gedächtnis nimmt, zum Beispiel https://pypi.python.org/pypi/memory_profiler

P. S. Statt

 if (key1, key2) in counts: 
      counts[key1, key2] += 1 
     else: 
      counts[key1, key2] = 1 

tun Sie

from collections import defaultdict 
... 
counts = defaultdict(int) 
... 
counts[(key1, key2)] += 1 
0

Man könnte so etwas versuchen:

import csv 

def get_counts(filepath): 

    data = csv.reader(open(filepath), delimiter=',') 
    # Remove the first line if headers 
    fields = data.next() 
    counts = {} 

    [count[row[0], row[1]] = count.get((row[0], row[1]), 0) + 1 for row in data] 

    return counts 
0

versuchen, diese

from collection import Counter 
import csv 

myreader = csv.reader(open(filename, 'r')) 
Counter([each[:-1] for row in myreader]) 

Hoffnung, das hilft.

Verwandte Themen