Предотвращение наследования дескриптора файла в многопроцессорной библиотеке lib
Использование многопроцессорной обработки в окнах, похоже, что все открытые дескрипторы файлов наследуются порожденными процессами. Это имеет неприятный побочный эффект от их блокировки.
Меня интересует:
1) Предотвращение наследования
2) Способ освобождения файла из порожденного процесса
Рассмотрим следующий код, который отлично работает на OSX, но падает на окна в 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()
Ответы
Ответ 1
Метод fileno()
возвращает номер файла, назначенный библиотекой времени выполнения. После номера файла вы можете вызвать msvcrt.get_osfhandle()
, чтобы получить дескриптор файла Win32. Используйте этот дескриптор в вызове SetHandleInformation
. Возможно, что-то вроде следующего:
win32api.SetHandleInformation(
msvcrt.get_osfhandle(testFile.fileno()),
win32api.HANDLE_FLAG_INHERIT,
0)
Я не уверен в точном использовании модуля win32api
, но это должно помочь устранить разрыв между файловым объектом Python и дескриптором Win32.
Ответ 2
Я не знаю о модуле многопроцессорности, но с модулем subprocess вы можете поручить ему не наследовать никаких файловых дескрипторов
Если значение close_fds истинно, все дескрипторы файлов, кроме 0, 1 и 2, будут закрыты до выполнения дочернего процесса. (Только для Unix). Или, в Windows, если close_fds истинно, тогда никакие дескрипторы не будут унаследованы дочерним процессом. Обратите внимание, что в Windows вы не можете установить close_fds в true, а также перенаправить стандартные дескрипторы, установив stdin, stdout или stderr.
В качестве альтернативы вы можете закрыть все дескрипторы файлов в дочернем процессе с помощью os.closerange
Закройте все дескрипторы файлов из fd_low (включительно) в fd_high (исключая), игнорируя ошибки. Доступность: Unix, Windows.
Ответ 3
После открытия дескриптора файла вы можете использовать функцию SetHandleInformation(), чтобы удалить флаг HANDLE_FLAG_INHERIT
.
Ответ 4
Я столкнулся с этой проблемой при использовании вращающегося журнала и многопроцессорности. Когда родительский процесс пытается повернуть журнал, он терпит неудачу с помощью
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/