防止在多进程库中文件句柄继承
在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()
5 个回答
在你打开一个文件的句柄之后,可以使用 SetHandleInformation()
这个函数来去掉 HANDLE_FLAG_INHERIT
这个标志。
我对 multiprocessing 模块不太了解,不过使用 subprocess 模块时,你可以告诉它不要继承任何文件描述符:
如果设置
close_fds
为真,那么在执行子进程之前,除了 0、1 和 2 这三个文件描述符外,其他的都会被关闭。(仅限 Unix 系统)。在 Windows 系统上,如果close_fds
为真,那么子进程不会继承任何句柄。需要注意的是,在 Windows 上,你不能同时将close_fds
设置为真,并通过设置stdin
、stdout
或stderr
来重定向标准句柄。
另外,你也可以在子进程中使用 os.closerange 来关闭所有文件描述符:
关闭从
fd_low
(包含)到fd_high
(不包含)之间的所有文件描述符,忽略错误。适用系统:Unix 和 Windows。
fileno()
方法会返回一个文件号,这个文件号是由运行时库分配的。拿到这个文件号后,你可以调用 msvcrt.get_osfhandle()
来获取 Win32 的文件句柄。然后,你可以用这个句柄去调用 SetHandleInformation
。所以,像下面这样的代码可能会有效:
win32api.SetHandleInformation(
msvcrt.get_osfhandle(testFile.fileno()),
win32api.HANDLE_FLAG_INHERIT,
0)
我对 win32api
模块的具体用法不是很确定,但这应该能帮助你理解 Python 文件对象和 Win32 句柄之间的关系。