tempfile.mkstemp too many open files

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
pyseidon
User
Beiträge: 19
Registriert: Donnerstag 24. September 2009, 20:25

Hallo,

folgende Situation. Über einen XML Gatway werden mehrere tausend XML-Dateien abgefragt. Diese werden dann mit SAX verarbeitet. Dafür muss ich die Dateien kurz zwischenspeichern. Mittels mkstemp erzeuge ich mir das File, speichere die Daten und lösche die Datei wieder. Trotzdem kommt nach einiger Zeit der Fehler "too many open files". Der Nachfolgende Code ist beispielhaft (die Schleife gibt es sonst nicht), illustriert aber mein Problem:

Code: Alles auswählen

#/usr/bin/env python

import tempfile
import os
import time

for i in range(1,1025):
    __, tmp_name = tempfile.mkstemp()
    with open(tmp_name, 'wb') as f:
        f.write("Hello World")
    #sax.parse(tmp_name, ContentHandler())
    os.remove(tmp_name)
    time.sleep(1)
Wenn ich aber folgenden Code verwende kommt keine Fehlermeldung. Kann man gut nachvollziehen wenn man in /proc/PID/fd nachschaut. Bei obigen Code steht jedes tempfile als deleted da. Bei unterem Code sehe ich kein File.

Code: Alles auswählen

#/usr/bin/env python

import tempfile
import os
import time

for i in range(1,1025):
    outfd, tmp_name = tempfile.mkstemp()
    outsock = os.fdopen(outfd, 'wb')
    outsock.write("Hello World")
    outsock.close()
    #sax.parse(tmp_name, ContentHandler())
    os.remove(tmp_name)
    time.sleep(1)
Kann mir bitte jemand erklären warum ich mit obigen Code in "too many open files" renne und mit unterem nicht?

Grüße
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

pyseidon hat geschrieben:Diese werden dann mit SAX verarbeitet.
Du armer :mrgreen:
pyseidon hat geschrieben: Dafür muss ich die Dateien kurz zwischenspeichern.
Muss man das echt? Wobei ich ja eh die ElementTree-API praktisch immer SAX vorziehen würde.

@Frage:
Du schließt ja die offenen Dateien nicht:
Doku zu mkstemp hat geschrieben: mkstemp() returns a tuple containing an OS-level handle to an open file (as would be returned by os.open()) and the absolute pathname of that file, in that order.
Die Datei ist also schon offen - ``os.fdopen`` wird die Datei also nicht wirklich öffnen, sondern vom OS den Handler übergeben bekommen. Mit Deiner ersten Lösung hast Du eigentlich eine Datei unabhängig vom ``mkstemp``-Aufruf ein zweites Mal geöffnet... k.A. welche Nebeneffekte das haben kann.

Probiers doch mal so:

Code: Alles auswählen

handle, filename = mkstemp()

print handle, filename
> 3 c:\dokume~1\nelson\lokale~1\temp\tmpk_qvi1

with os.fdopen(handle, "w") as f:
    f.write("Hello World")
Letztlich Deine zweite Lösung, nur mit ``with`` :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Sirius3
User
Beiträge: 17844
Registriert: Sonntag 21. Oktober 2012, 17:20

@pyseidon: »sax.parse« nimmt jedes file-like Objekt, also entweder Deinen Socket direkt, oder eben über »parseString« falls Du schon einen String hast, oder … . Es gibt da unendlich viele Möglichkeiten, ohne dass man temporäre Dateien braucht.

@Hyperion: ich hatte schon xml-Dateien, die waren für ElementTree zu komplex (mehrere GB), in 99% der Fälle ist es, wie Du schon gesagt hast, genau umgekehrt und SAX ist zu komplex für die Datei.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Sirius3 hat geschrieben: @Hyperion: ich hatte schon xml-Dateien, die waren für ElementTree zu komplex (mehrere GB), in 99% der Fälle ist es, wie Du schon gesagt hast, genau umgekehrt und SAX ist zu komplex für die Datei.
Auch für ``iterparse``? (Aus dem ``lxml``-Modul)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
pyseidon
User
Beiträge: 19
Registriert: Donnerstag 24. September 2009, 20:25

@Hyperion
Danke, das hatte ich in der Doku übersehen. Das erklärt dann warum bei der ersten Variante die Datei nicht geschlossen wurde.

Bezüglich SAX. In dem Fall könnte ich vermutlich auch auf die ElementTreeAPI umschwenken. Die Dateien sind recht klein. Wobei ich hier immer mit der Namespace angabe hadere. Ansonsten hantieren wir auch mit sehr großen XML-Dateien und da ist der SAX-Parser doch recht angenehm. Passt halt nicht alles in dem RAM. ;)

Bezüglich lxml. Die ElementTreeAPI hat auch ein iterparse. Ist hier lxml "besser"? Allerdings muss ich mit den Standardsachen von Python 2.6 auskommen. :roll:

@Sirius3
``parseString`` werde ich mal ausprobieren. Dann hätte sich das Zwischenspeichern erledigt.
Antworten