在Windows上使用python 2.7.4(注意:WinXP - 下面的评论者建议在Win7上正常工作),我有一个脚本创建几个线程,每个线程通过Popen运行子进程,stdout / stderr重定向到文件和调用等待() . 每个Popen都有自己的stdout / stderr文件 . 在每个进程返回后,我有时必须删除文件(实际上将它们移动到别处) .
我发现在所有wait()调用返回之前我都无法删除stdout / stderr日志 . 在此之前,我得到“WindowsError:[错误32]该进程无法访问该文件,因为它正被另一个进程使用” . 看起来,只要至少有一个子进程打开,Popen就会以某种方式保留stderr文件,即使这些文件没有共享 .
测试代码重现如下 .
C:\ test1.py
import subprocess
import threading
import os
def retryDelete(p, idx):
while True:
try:
os.unlink(p)
except Exception, e:
if "The process cannot access the file because it is being used by another process" not in e:
raise e
else:
print "Deleted logs", idx
return
class Test(threading.Thread):
def __init__(self, idx):
threading.Thread.__init__(self)
self.idx = idx
def run(self):
print "Creating %d" % self.idx
stdof = open("stdout%d.log" % self.idx, "w")
stdef = open("stderr%d.log" % self.idx, "w")
p = subprocess.Popen("c:\\Python27\\python.exe test2.py %d" % self.idx,
stdout=stdof, stderr = stdef)
print "Waiting %d" % self.idx
p.wait()
print "Starting deleting logs %d" % self.idx
stdof.close()
stdef.close()
retryDelete("stderr%d.log" % self.idx, self.idx)
print "Done %d" % self.idx
threads = [Test(i) for i in range(0, 10)]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
C:\ test2.py:
import time
import sys
print "Sleeping",sys.argv[1]
time.sleep(int(sys.argv[1]))
print "Exiting",sys.argv[1]
如果运行此命令,您将看到每个retryDelete()都会对文件访问错误进行旋转,直到所有子进程都完成为止 .
UPDATE :即使stdof和stdef文件描述符未传递给Popen构造函数,也会出现问题 . 但是,如果删除了Popen并且用time.sleep(self.idx)替换了wait(),则不会发生(即删除立即发生) . 由于Popen似乎对未传递给它的文件描述符有影响,我想知道这个问题是否与句柄继承有关 .
UPDATE :close_fds = True给出错误(重定向stdout / stderr时Windows不支持),并且在wait()调用之后用del p删除Popen对象对问题没有影响 .
UPDATE :使用sysinternals进程资源管理器查找具有文件句柄的进程 . 将测试减少到仅2个线程/儿童,并使第二个线程保持打开状态很长时间 . 句柄搜索显示唯一具有stderr0.log句柄的进程是父python进程,它有两个句柄打开 .
UPDATE :对于我目前的紧急使用情况,我仍然对这个问题的答案感兴趣 . 对我来说这感觉就像一个特定于WinXP的错误,但是它只是做错了什么 .
2 回答
这个问题很老了,这个BUG已在Python 3.4上修复 . 为了记录,这里有一个hacky技巧,我们一直用于解决python 2.7或python 3.3-上的问题
==>在启动子进程之前,请调用以下函数
此函数将处理已打开的最后100个文件描述符,并将其设置为“无继承模式”,这将修复该错误 . 如果需要,可以增加100号码 .
您可以尝试更新到Win7,我知道这是WinXP用户中的常见错误 .