WindowsError: [错误 5] 访问被拒绝,无法终止子进程(python)

10 投票
1 回答
10446 浏览
提问于 2025-04-16 15:14

我有一个Python脚本,它在一个循环中运行,里面调用了一个程序A,通过subprocess.Popen来等待它的输出,然后保存这个输出,再继续调用它,反复进行下去。(这个过程会根据我设定的输入次数不断重复)

这个脚本里有一个定时器,意思是如果程序A运行时间超过了我设定的某个阈值,脚本就会用process.kill()来结束这个进程,然后继续进行下一次循环。

问题是,虽然在300次运行的时候一切看起来都很正常,但有时候我会遇到这样的错误:

    File "C:\Python27\lib\subprocess.py", line 1002, in terminate
    _subprocess.TerminateProcess(self._handle, 1)
    WindowsError: [Error 5] Access is denied

然后脚本就崩溃了。

相关的脚本部分:

timeout = TIME_CONST
for run in runs:
    killed = False
    start = time.clock()
    p = subprocess.Popen("SOME.CMD", cwd=r"some_dir") 
    # Monitor process. If it hits threshold, kill it and go to the next run
    while p.poll() is None:
        time.sleep(20) 
        secs_passed = time.clock() - start

        ### the following was my initial buggy line ###
        #if secs_passed >= timeout: 

        ### corrected line after jedislight's answer ###
        #if the time is over the threshold and process is still running, kill it
        if secs_passed >= timeout and p.poll is None: 
            p.kill()
            killed = True  
            break
    if killed: continue   

你们有什么建议,觉得问题可能出在哪里吗?

补充: 我已经接受了答案并修复了代码。感谢@jedislight的反馈!

1 个回答

8

你在调用 p.poll() 和 p.kill() 之间隔了20秒。这段时间内,进程可能已经结束了。我建议你调整一下时间,让这两个操作在同一时间段内进行,这样就能避免去杀死一个已经结束的进程。下面是一个在 iPython 中运行的例子,展示了在杀死一个已经完成的进程时出现的类似错误:

In [2]: import subprocess

In [3]: p = subprocess.Popen("dir")

In [4]: p.poll()
Out[4]: 0

In [5]: p.kill()
---------------------------------------------------------------------------
WindowsError                              Traceback (most recent call last)

C:\Users\---\<ipython console> in <module>()

C:\Python26\lib\subprocess.pyc in terminate(self)
    947             """Terminates the process
    948             """
--> 949             _subprocess.TerminateProcess(self._handle, 1)
    950
    951         kill = terminate

WindowsError: [Error 5] Access is denied

即使你在检查进程状态后立刻去杀死它,如果在执行下一行代码之前进程已经结束了,也会出现问题。我还建议你加一个 try-catch 结构来处理这个异常,如果发生了,就再检查一次,看看进程是否真的完成了。

撰写回答