2009-06-04 11 views
11

Al usar el multiprocesamiento en Windows, parece que los identificadores de archivos abiertos se heredan por procesos generados. Esto tiene el desagradable efecto secundario de bloquearlos.Prevención de la herencia del identificador de archivos en multiprocesamiento lib

estoy interesado en cualquiera de los dos:
1) Prevención de la herencia
2) Una manera de liberar el archivo del proceso generado

considere el siguiente código que funciona muy bien en OSX, pero se bloquea en las ventanas en 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() 

Respuesta

0

Después de abrir un identificador de archivo, puede utilizar la función SetHandleInformation() para quitar la bandera HANDLE_FLAG_INHERIT.

+0

¿Cómo se obtiene el identificador de archivo de algo creado con open(), no os.open()? – 14256424

1

No sé sobre el módulo de multiprocesamiento , pero con el módulo subprocess le puede dar instrucciones a no hereda ningún descriptores de archivo:

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.

Alternativamente, usted podría cerrar todos los descriptores de fichero en su proceso hijo con os.closerange

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

+2

Conozco el indicador de subproceso, pero específicamente estoy preguntando sobre el módulo de multiprocesamiento. Además, si tenemos otro conducto o archivo que queremos heredar, el indicador close_fds es un poco pesado. – 14256424

+0

@vilalian En el caso en que desee conservar los descriptores de archivos heredados, deberá pasar esta información al subproceso para que sepa qué descriptores de archivos no cerrar. No hay otra manera. – lothar

4

el método fileno() devuelve el número de expediente asignado por la biblioteca en tiempo de ejecución. Dado el número de archivo, puede llamar al msvcrt.get_osfhandle() para obtener el manejador del archivo Win32. Use este identificador en la llamada al SetHandleInformation. Así que algo como lo siguiente puede trabajar:

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

No estoy seguro de la utilización adecuada del módulo win32api, pero esto debería ayudar a cerrar la brecha entre un objeto de archivo Python y un mango de Win32.

0

He encontrado este problema cuando uso un registro rotativo y multiprocesamiento. Cuando el proceso padre intenta girar el registro, se produce un error con un

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

basado en algunas de las otras respuestas, la siguiente es una solución de trabajo en Python 2.7 para evitar controladores de archivos de registro desde sido heredada

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 

Tenga en cuenta que este problema era una dirección en python 3.4. para obtener más información, vea https://www.python.org/dev/peps/pep-0446/

Cuestiones relacionadas