Предотвращение наследования дескриптора файла в многопроцессорной библиотеке lib - PullRequest
11 голосов
/ 04 июня 2009

При использовании многопроцессорной обработки в Windows все дескрипторы открытых файлов наследуются порожденными процессами. Это имеет неприятный побочный эффект их блокировки.

Меня интересует либо:
1) Профилактика наследства
2) Способ освободить файл от порожденного процесса

Рассмотрим следующий код, который отлично работает на OSX, но вылетает в Windows по адресу 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()

Ответы [ 4 ]

4 голосов
/ 12 июня 2009

Метод fileno() возвращает номер файла, назначенный библиотекой времени выполнения. Учитывая номер файла, вы можете затем позвонить msvcrt.get_osfhandle(), чтобы получить дескриптор файла Win32. Используйте этот дескриптор при вызове SetHandleInformation. Так что может работать что-то вроде следующего:

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

Я не уверен в точном использовании модуля win32api, но это должно помочь преодолеть разрыв между файловым объектом Python и дескриптором Win32.

1 голос
/ 04 июня 2009

Я не знаю о модуле multiprocessing , но с модулем подпроцесс вы можете указать ему не наследовать дескрипторы файлов:

Если close_fds имеет значение true, все файловые дескрипторы, кроме 0, 1 и 2, будут закрыты до выполнения дочернего процесса. (Только для Unix). Или в Windows, если close_fds имеет значение true, тогда никакие дескрипторы не будут наследоваться дочерним процессом. Обратите внимание, что в Windows вы не можете установить для close_fds значение true, а также перенаправить стандартные дескрипторы, установив stdin, stdout или stderr.

В качестве альтернативы вы можете закрыть все файловые дескрипторы в вашем дочернем процессе с помощью os.closerange

Закрыть все файловые дескрипторы от fd_low (включительно) до fd_high (эксклюзив), игнорируя ошибки. Наличие: Unix, Windows.

0 голосов
/ 30 марта 2016

Я столкнулся с этой проблемой при использовании ротационного журнала и многопроцессорной обработки. Когда родительский процесс пытается повернуть журнал, он завершается с ошибкой

WindowsError: [Ошибка 32] Процесс не может получить доступ к файлу, поскольку он используется другим процессом

Основываясь на некоторых других ответах, ниже приведено рабочее решение в Python 2.7 для предотвращения наследования обработчиков файлов журнала

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

Обратите внимание, что эта проблема была несколько решена в Python 3.4. для получения дополнительной информации см. https://www.python.org/dev/peps/pep-0446/

0 голосов
/ 04 июня 2009

После открытия дескриптора файла вы можете использовать функцию SetHandleInformation (), чтобы удалить флаг HANDLE_FLAG_INHERIT.

...