python 等待线程结束_关于python:subprocess.wait()不等待Popen进程完成(使用线程时)?...

使用subprocess.Popen()从我的python脚本使用线程生成同一应用程序的多个实例以使其同时运行时,遇到了一些问题。在每个线程中,我使用popen()调用运行应用程序,然后通过调用wait()等待它完成。问题似乎是wait()调用实际上没有等待进程完成。我仅使用一个线程进行了实验,并在进程开始和结束时打印出了文本消息。所以线程函数看起来像这样:

1

2

3

4

5

6

7

8def 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()

但是,即使我只使用一个线程,它也会在出现任何"已完成进程..."消息之前打印出几条"正在启动进程..."消息。是否有wait()实际上没有等待的情况?我有几个不同的外部应用程序(C ++控制台应用程序),这些应用程序又将同时运行多个实例,对于某些实例,我的代码有效,但对于其他实例,则不会。外部应用程序是否存在某些问题,以某种方式影响对wait()的调用?

用于创建线程的代码如下所示:

1

2

3

4

5for i in range(1):

t = Thread(target=worker)

t.daemon = True

t.start()

q.join() # Wait for the queue to empty

更新1:

我还应该补充一点,对于某些外部应用程序,有时会得到-1073471801的返回码(proc.returncode)。例如,一个外部应用程序将在前两次调用Popen时给出返回代码,但在后两次不给出(当我有四个作业时)。

更新2:

为了解决问题,现在队列中有四个作业,这是四个不同的测试用例。当我运行代码时,对于外部应用程序之一,前两个Popen调用生成返回代码-1073471801。但是,如果我打印出Popen调用的确切命令,并在命令窗口中运行它,则执行该命令不会出现任何问题。

解决了!

我设法解决了自己遇到的问题。我认为问题是我缺乏线程编程经验。我错过了这样一个事实,当我创建了第一个工作线程时,它们将继续存在直到python脚本退出。每次我将新项目放入队列时,我都会错误地创建更多的工作线程(对于要运行的每个外部程序,我都会成批执行)。因此,当我进入第四个外部应用程序时,尽管我只以为有一个线程,但我同时运行了四个线程。

尝试print proc.wait()并检查返回码。

您也可以使用check_call()代替Popen。 即使shell=True,check_call()也要等待命令完成,然后返回作业的退出代码。

使用shell = True似乎实际上并没有等待。

似乎时Popen也不会等待。

可悲的是,当使用shell=True运行子流程时,wait()将仅等待sh子流程完成,而不会等待命令cmd。

我将建议是否可以不使用shell=True,如果不可能的话,您可以创建一个类似于此答案的进程组,并使用os.waitpid来等待进程组,而不仅仅是shell进程。

希望这对您有所帮助:)

对于我自己,我从未发现shell=True是必要或有用的情况。 如果您从其他地方获取字符串,它可以让您变得懒惰而不会将字符串分割开,但是缺少引号的需要(在不同平台上具有不同的解析)是非常宝贵的-我更喜欢传递可迭代的字符串而不是使用 引用值,在拆分时必须要小心。

@Chris:甚至是文档建议也不要使用shell=True,特别是当要执行的数据来自不受信任的来源时,以避免注入外壳。

在某些情况下,如果不使用shell= True,将会得到OSError: [Errno 2] No such file or directory

我也遇到了问题,但是受到了你的启发。

我的看起来像这样,并且做工精美:

1

2

3

4

5

6startupinfo = subprocess.STARTUPINFO()

startupinfo.dwFlags = subprocess.STARTF_USESHOWWINDOW

startupinfo.wShowWindow = subprocess.SW_HIDE

proc = subprocess.Popen(command, startupinfo=startupinfo)

proc.communicate()

proc.wait()

请注意,这也隐藏了窗口。

确保您正在调用的所有应用程序在完成时都具有有效的系统返回码

<think>我们被要求使用中文回答,并且遵循特定的格式要求。用户的问题是如何使用Pythonsubprocess.Popen来检测子进程是否结束。 根据引用[1]和引用[3],我们知道subprocess.Popen提供了几种方法来与子进程交互,包括检测其是否结束。 方法总结: 1. 使用poll()方法:检查子进程是否已经终止。如果终止则返回returncode,否则返回None。 2. 使用wait()方法:等待进程终止,并返回returncode。注意:这会阻塞当前线程直到子进程结束。 3. 使用communicate()方法:与进程交互,等待进程结束,并返回输出和错误信息(如果有)。这个方法也会阻塞直到子进程结束。 另外,引用[3]提到Popen对象有一个属性returncode,当子进程尚未结束为None,结束进程的退出状态码(整数)。 因此,我们可以通过以下方式检测子进程是否结束: - 轮询poll()方法(非阻塞) - 使用wait()方法(阻塞) - 使用communicate()方法(阻塞,并获取输出) - 检查returncode属性(非阻塞,但需要结合进程状态) 下面我们分别说明。 根据引用[1]和引用[2]的示例,我们可以这样操作: 示例1:使用poll()非阻塞检查 process = subprocess.Popen(['some_command']) while process.poll() is None: # 子进程还在运行 time.sleep(0.1) # 避免忙等待,适当休眠 print("子进程结束,返回码:", process.returncode) 示例2:使用wait()阻塞等待 process = subprocess.Popen(['some_command']) returncode = process.wait() # 阻塞直到子进程结束 print("子进程结束,返回码:", returncode) 示例3:使用communicate()(当需要与子进程交互process = subprocess.Popen(['some_command'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) # communicate()等待进程结束,并返回输出和错误 stdout, stderr = process.communicate() print("子进程结束,返回码:", process.returncode) 注意:communicate()也会阻塞直到子进程结束,并且它会读取stdout和stderr直到结束,因此适用于需要获取输出的情况。 另外,引用[4]提到了一个挂起的例子,实际上是因为子进程等待输入,而父进程没有提供输入。在这种情况下,如果我们需要与子进程交互,那么应该避免使用stdin=PIPE,否则子进程可能会因为等待输入而挂起。如果确实需要交互,则必须通过communicate()提供输入。 因此,根据用户的需求(只是检测是否结束): - 如果需要获取输出,且想阻塞,用poll()轮询。 - 如果需要获取输出,且可以阻塞,用wait()。 - 如果需要获取输出,用communicate()。 下面我们给出一个代码示例,展示如何使用poll()来非阻塞地检测子进程是否结束。</think>### 如何用 Python subprocess.Popen 检测子进程结束Python使用 `subprocess.Popen` 检测子进程是否结束,主要有以下四种方法: #### 1. **轮询检测(非阻塞)** 使用 `poll()` 方法定期检查进程状态: ```python import subprocess import time proc = subprocess.Popen(['ping', 'example.com']) while True: return_code = proc.poll() # 返回 None 表示仍在运行 if return_code is not None: print(f"子进程结束,退出码: {return_code}") break print("子进程运行中...") time.sleep(1) # 避免CPU占用过高 ``` #### 2. **阻塞等待** 使用 `wait()` 方法阻塞当前线程直到进程结束: ```python proc = subprocess.Popen(['notepad.exe']) return_code = proc.wait() # 阻塞等待 print(f"进程结束,退出码: {return_code}") ``` #### 3. **实交互检测** 使用 `communicate()` 获取输出并等待结束: ```python proc = subprocess.Popen( ['python', '-c', 'import time; time.sleep(3); print("Done")'], stdout=subprocess.PIPE ) # 阻塞直到进程结束并捕获输出 output, _ = proc.communicate() print(f"输出: {output.decode()}, 退出码: {proc.returncode}") ``` #### 4. **检查 returncode 属性** 直接检查进程对象的属性(需确保进程已启动): ```python proc = subprocess.Popen(['calc.exe']) if proc.returncode is None: print("进程仍在运行") else: print(f"进程结束,退出码: {proc.returncode}") ``` > **关键区别** > - `poll()`:非阻塞,适合需持续监控的场景 > - `wait()`/`communicate()`:阻塞,适合需等待结果的场景 > - `returncode`:直接访问状态属性(需结合其他方法使用)[^1][^3] --- ### 相关问题 1. 如何强制终止 `subprocess.Popen` 创建的子进程? 2. `subprocess.Popen` 和 `os.system()` 在进程管理上有何本质区别? 3. 当子进程卡死,如何实现超自动终止功能? 4. 如何实捕获子进程的标准输出而阻塞主程序? [^1]: 通过 Popen,你可以更方便地捕获进程的标准输出和标准错误,甚至可以与进程进行更复杂的交互。 [^2]: Python subprocess.Popen 打开第三方程序。在 Python 中,subprocess.Popen是启动和管理第三方程序的强大工具。 [^3]: Popen.returncode 子程序的返回值,由poll()或者wait()设置,间接地也由communicate()设置。 [^4]: 模拟一个外部命令,该命令会无限期地循环读取输入。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值