subprocess.wait() 未等待 Popen 进程完成(使用线程时)?
我在用 subprocess.Popen()
从我的 Python 脚本中同时启动多个相同应用程序的实例时遇到了一些问题。我是通过线程来实现的,每个线程里我用 popen()
来运行应用程序,然后再用 wait()
等待它完成。问题是,wait()
似乎并没有真正等待进程结束。我尝试只用一个线程,并在进程开始和结束时打印一些文本消息。这样线程的函数大概是这样的:
def worker():
while True:
job = q.get() # q is a global Queue of jobs
print('Starting process %d' % job['id'])
proc = subprocess.Popen(job['cmd'], shell=True)
proc.wait()
print('Finished process %d' % job['id'])
job.task_done()
但是即使我只用一个线程,它也会在任何 "Finished process..." 消息出现之前,打印出好几条 "Starting process..." 的消息。有没有可能在某些情况下 wait()
不会真正等待呢?我有几个不同的外部应用程序(C++ 控制台应用),它们会同时运行多个实例,对其中一些应用,我的代码能正常工作,但对其他的就不行。是不是外部应用程序本身有问题,导致 wait()
的调用受到影响呢?创建线程的代码大概是这样的:
for i in range(1):
t = Thread(target=worker)
t.daemon = True
t.start()
q.join() # Wait for the queue to empty
更新 1:
我还要补充一点,对于某些外部应用程序,我有时会得到一个返回码(proc.returncode
)为 -1073471801。例如,其中一个外部应用在调用 Popen
的前两次会返回这个码,但在后两次(当我有四个任务时)就不会了。
更新 2:
为了澄清一下,现在我有四个任务在队列中,都是四个不同的测试用例。当我运行我的代码时,对于一个外部应用,前两次 Popen
调用会生成返回码 -1073471801。但是如果我打印出 Popen
调用的确切命令,并在命令窗口中运行它,它就能正常执行。
解决了! 我终于解决了我遇到的问题。我觉得问题出在我对线程编程的经验不足。我没有意识到,当我创建了第一个工作线程后,它们会一直存在,直到 Python 脚本退出。每次我在队列中放新项目时,我错误地创建了更多的工作线程(我对每个想要运行的外部程序都是批量处理)。所以当我到达第四个外部应用时,实际上有四个线程同时在运行,尽管我只认为我有一个。
4 个回答
确保你调用的所有应用程序在结束时都有有效的系统返回代码。
很遗憾,当你使用 shell=True
来运行子进程时,wait(
只会等待 sh
这个子进程结束,而不会等你实际运行的命令 cmd
完成。
我建议如果可以的话,尽量不要使用 shell=True
。如果实在不能,你可以像这个 回答 中提到的那样,创建一个进程组,然后使用 os.waitpid 来等待整个进程组,而不仅仅是等待 shell 进程。
希望这些信息对你有帮助 :)
你也可以用 check_call()
来代替 Popen。check_call()
会等命令执行完毕,即使你设置了 shell=True
,然后它会返回这个任务的退出代码。