2009-06-04 3 views
11

Bei Verwendung von Multiprocessing unter Windows scheint es, dass offene Dateihandles von erzeugten Prozessen vererbt werden. Dies hat den unangenehmen Nebeneffekt, sie zu verriegeln.Dateihandlevererbung in Multiprocessing-Lib verhindern

Ich habe Interesse an entweder:
1) Verhindern die Vererbung
2) eine Möglichkeit, die Datei aus dem erzeugten Prozess zur Freigabe

den folgenden Code betrachten, die auf OSX, aber stürzt auf Windows funktioniert gut bei os.rename

from multiprocessing import Process 
import os 

kFileA = "a.txt" 
kFileB = "b.txt" 

def emptyProcess(): 
    while 1: 
     pass 

def main(): 
    # Open a file and write a message 
    testFile = open(kFileA, 'a') 
    testFile.write("Message One\n") 

    # Spawn a process 
    p = Process(target=emptyProcess) 
    p.start() 

    # Close the file 
    testFile.close() 

    # This will crash 
    # WindowsError: [Error 32] The process cannot access the file 
    #    because it is being used by another process 
    os.rename(kFileA, kFileB) 

    testFile = open(kFileA, 'a') 
    testFile.write("Message Two\n") 
    testFile.close() 

    p.terminate() 


if __name__ == "__main__": 
    main() 

Antwort

0

Nachdem Sie eine Datei-Handle öffnen, können Sie die SetHandleInformation() Funktion verwenden, um die HANDLE_FLAG_INHERIT Flags zu entfernen.

+0

Wie erhält man das Dateihandle von etwas, das mit open(), nicht os.open() erstellt wurde? – 14256424

1

Ich weiß nicht, über die Multiprozessing Modul, aber mit dem subprocess Modul können Sie es anweisen, keine Datei-Deskriptoren erben:

If close_fds is true, all file descriptors except 0, 1 and 2 will be closed before the child process is executed. (Unix only). Or, on Windows, if close_fds is true then no handles will be inherited by the child process. Note that on Windows, you cannot set close_fds to true and also redirect the standard handles by setting stdin, stdout or stderr.

Alternativ können Sie alle Datei-Deskriptoren in Ihrem Kind Prozess schließen mit os.closerange

Close all file descriptors from fd_low (inclusive) to fd_high (exclusive), ignoring errors. Availability: Unix, Windows.

+2

Ich kenne das Subprozess-Flag, aber ich frage speziell nach dem Multiprocessing-Modul. Außerdem, wenn wir eine andere Pipe oder Datei haben, die wir erben wollen, ist das close_fds-Flag ein wenig schwergewichtig. – 14256424

+0

@vilalian Wenn Sie geerbte Dateideskriptoren beibehalten möchten, müssen Sie diese Informationen an den Unterprozess weiterleiten, damit sie weiß, welche Dateideskriptoren nicht geschlossen werden sollen. Es gibt keinen anderen Weg. – lothar

4

fileno() die Methode gibt die Dateinummer, wie durch die Laufzeitbibliothek zugeordnet. Mit der Dateinummer können Sie dann msvcrt.get_osfhandle() aufrufen, um das Win32-Dateihandle abzurufen. Verwenden Sie dieses Handle im Aufruf von SetHandleInformation. So etwas wie die folgenden funktionieren kann:

win32api.SetHandleInformation(
    msvcrt.get_osfhandle(testFile.fileno()), 
    win32api.HANDLE_FLAG_INHERIT, 
    0) 

Ich bin nicht sicher über die genaue Verwendung des win32api Modul, aber dies sollte die Lücke zwischen einem Python-Datei-Objekt und einem Win32-Handle überbrücken.

0

Ich habe dieses Problem bei Verwendung eines rotierenden Protokolls und Multiprocessing aufgetreten. Wenn der übergeordnete Prozess das Protokoll zu drehen versucht, es mit einem auf einigen der anderen Antworten basieren

WindowsError: [Error 32] The process cannot access the file because it is being used by another process

ausfällt, eine der folgenden ist eine Arbeitslösung in Python 2.7 zu verhindern Protokolldatei Handler geerbt

fd = logging.getLogger().handlers[0].stream.fileno() # The log handler file descriptor 
fh = msvcrt.get_osfhandle(fd) # The actual windows handler 
win32api.SetHandleInformation(fh, win32con.HANDLE_FLAG_INHERIT, 0) # Disable inheritance 

Bitte beachten Sie, dieses Problem wurde etwas in Python 3.4 angesprochen. Weitere Informationen finden Sie unter https://www.python.org/dev/peps/pep-0446/