2017-07-04 3 views
0

Meine Funktion ist auf die folgende Weise Datei zeilenweise zu behandeln. Es sind mehrere Fehlermuster definiert, die für jede Zeile gelten müssen. Ich benutze multiprocessing.Pool, um die Datei in Block zu behandeln.Python re.match rekursiven Anruf Speicherleck

Die Speicherbelegung erhöht sich für eine 1G-Datei auf 2G. Und bleibt in 2G auch nach der Dateiverarbeitung. Datei am Ende geschlossen.

Wenn ich den Aufruf von re_pat.match auskommentieren, ist die Speichernutzung normal und hält unter 100 MB.

verwende ich re in einer falschen Weise? Ich kann keinen Weg finden, das Speicherleck zu beheben.

def line_match(lines, errors) 
    for error in errors: 
     try: 
      re_pat = re.compile(error['pattern']) 
     except Exception: 
      print_error 
      continue 

     for line in lines: 
      m = re_pat.match(line) 
      # other code to handle matched object 



def process_large_file(fo): 
    p = multiprocessing.Pool() 
    while True: 
     lines = list(itertools.islice(fo, line_per_proc)) 
     if not lines: 
      break 
     result = p.apply_async(line_match, args=(errors, lines)) 

Hinweise: auslassen ich einige Code, wie ich die signifikanten Unterschied denken, ist mit/ohne re_pat.match (...)

+1

Was genau macht Ihr Code? Es ist nicht klar. –

+0

@ cᴏʟᴅsᴘᴇᴇᴅ Ich aktualisiere den Code-Einzug. Es wird eine Liste von Fehlermustern auf jede Zeile der Datei angewendet, um ein übereinstimmendes Objekt zu finden. – Mayling

+0

Schnelle Frage. Was sind Linien? Woher kommt das? –

Antwort

0

Ein paar Dinge ... Werfen Sie einen Blick auf die Nutzung von hier. Sie müssen einen Start- und einen Stop-Parameter angeben. Es scheint nicht so zu sein. Jeder Prozess arbeitet in den gleichen Zeilen von der Datei, auch nicht in eine Liste, weil Sie nicht alle Zeilen auf einmal brauchen - das ist verschwenderisch.

Sie müssen, so etwas tun:

line_per_proc = ... 

count = 0 
while True: 
    lines = itertools.islice(fo, start=line_per_proc, stop=lines_per_proc * (count + 1)) 
    if not lines: 
     break 
    result = p.apply_async(line_match, args=(errors, lines)) 
    count += 1 

nächste für jedes Muster, iterieren Sie über lines. Also, wenn Sie 10 Muster haben, iterieren Sie 10 Mal über dieselben Linien! Wenn Sie eine große Datei haben, ist dies besonders ineffizient, besonders wenn diese Zeilen als Liste geladen wurden!

Versuchen Sie folgendes:

def line_match(lines, errors): 
    # first, compile all your patterns 
    compiled_patterns = [] 
    for error in errors: 
     compiled_patterns.append(re.compile(error['pattern'])) 

    for line in lines: # lines is a generator, not a list 
     for pattern in compiled_patterns: 
      m = pattern.match(line) 
      # other code to handle matched object 

Dies sollte Ihnen eine Komplettlösung loszulegen helfen.

+0

Danke. Ich benutze die Liste, da ich einen Zeilenkontext benötige. (Ich werde auf Ihren Code verweisen, um meinen Code zu verfeinern). Ich habe Ihre Methode mit einer Liste von Mustern versucht, die das Speicherleckproblem nicht lösen können. Und ich bin mir ziemlich sicher, dass das Leck innerhalb von pattern.match passiert. – Mayling

+0

@Mayling Okay ... Sie können es nützlich finden, den Kompilierungsprozess zu umgehen und das Äquivalent von re.match auf Modulebene zu verwenden. Versuch es. –

+0

@COLDSPEED, Danke. Ich habe das versucht. Es verwendet mehr Speicher und viel langsamer. – Mayling

Verwandte Themen