如何使用Python的subprocess.Popen()在执行git命令时检测git挂起
如何使用Python的subprocess.Popen()在执行git命令时检测git挂起
以下是运行任意命令并返回其stdout数据,或在非零退出码时抛出异常的Python代码:
proc = subprocess.Popen( cmd, stderr=subprocess.STDOUT, # 合并stdout和stderr stdout=subprocess.PIPE, shell=True)
使用`communicate`方法等待进程退出:
stdoutdata, stderrdata = proc.communicate()
`subprocess`模块不支持超时(即在运行超过X秒的进程上终止它的能力),因此`communicate`可能需要很长时间才能运行。
在一个旨在在Windows和Linux上运行的Python程序中,实现超时的最简单方法是什么?
问题的出现的原因:在执行git命令时,有时会出现卡住的情况,即进程无法正常结束。
解决方法:通过在Python中使用subprocess.Popen()函数来检测git命令卡住的情况,并进行处理。具体的解决方法如下:
1. 创建一个Command类,用于执行git命令。
2. 在Command类中定义一个run()方法,接收一个超时参数。
3. 在run()方法中,创建一个target()函数,用于在单独的线程中执行git命令。
4. 在target()函数中,使用subprocess.Popen()函数来执行git命令,并使用communicate()方法与子进程进行通信。
5. 在run()方法中,创建一个线程,并将target()函数作为target参数传入。
6. 在run()方法中,使用join()方法等待线程执行完毕。
7. 判断线程是否仍在运行,如果是,则调用terminate()方法终止进程。
8. 打印进程的返回码。
以上是通过在单独的线程中执行git命令来检测卡住情况的解决方法。这种方法可以在不同的操作系统上使用,并且可以正常工作。在测试中,该方法在Linux和Windows上都可以正常工作。
但是需要注意的是,在Windows上使用shell=True参数时,需要使用subprocess.Popen("TASKKILL /F /PID {pid} /T".format(pid=self.process.pid))来终止进程。
如何使用Python的subprocess.Popen()检测git命令执行时的挂起
当使用subprocess.Popen()执行git命令时,有时候会遇到命令挂起的情况。下面是一个使用threading.Timer类简化jcollado的答案的示例代码:
import shlex from subprocess import Popen, PIPE from threading import Timer def run(cmd, timeout_sec): proc = Popen(shlex.split(cmd), stdout=PIPE, stderr=PIPE) timer = Timer(timeout_sec, proc.kill) try: timer.start() stdout, stderr = proc.communicate() finally: timer.cancel() # Examples: both take 1 second run("sleep 1", 5) # process ends normally at 1 second run("sleep 5", 1) # timeout happens at 1 second
这个解决方法简单且可移植。不需要使用lambda表达式,只需要使用Timer类的构造函数即可。
有人问为什么需要使用lambda表达式,其实不需要,可以直接使用绑定的proc.kill方法。
另外,有人要求提供一个使用示例,这里提供了两个示例。
有人反馈说jcollado的答案对他而言可行,但是这个解决方法在Windows 7上不起作用。
还有人说这个方法对他而言可行,但是在Windows上只能杀死父进程,不能杀死子进程。
有人发现当Popen的shell参数设置为True时,这个解决方法不起作用,请有人解释一下。
还有人在使用较短的定时器测试这段代码时发现了一个问题。在"finally"语句块中,需要将"timer.cancel()"方法包装在它自己的try/except语句中。在极少数情况下,当进程在代码执行之前被杀死时,可能会出现错误。代码示例如下:
finally: try: timer.cancel() except OSError as e: if 'No such process' not in str(e): raise OSError(e)
有人问如何判断进程是正常结束还是超时结束,可以在调用`timer.cancel()`之前使用`timer.isAlive()`方法判断。如果返回False,则表示进程正常结束。
这样,我们就可以使用Python的subprocess.Popen()和threading.Timer来检测git命令执行时是否挂起了。
问题的出现原因:
- 使用subprocess.Popen()执行git命令时,可能会导致git命令hang住,即无法正常执行和返回结果。
解决方法:
- 在Python 3.3+版本中,可以使用subprocess.check_output()方法来执行git命令,并设置timeout参数来限制命令执行的时间。
- check_output()方法会返回一个包含命令输出的字节字符串。
- 如果命令执行时出现非零的退出状态,check_output()方法会引发CalledProcessError异常。
- 需要注意的是,不要使用shell=True参数,除非命令确实需要该参数。如果使用了shell=True参数,check_output()方法可能会比timeout指定的时间更晚返回结果。
- 若要在Python 2.x版本中使用timeout功能,可以使用subprocess32模块的subprocess32.check_output()方法。
其他相关信息:
- 在Python 3.5+版本中,可以使用subprocess.run()方法并设置capture_output=True参数来执行git命令,并使用encoding参数来获取有用的输出。
- check_output()是获取输出的首选方法,它直接返回输出结果,不会忽略错误,而且一直可用。
- run()方法更加灵活,但默认情况下会忽略错误,需要额外的步骤才能获取输出。
- check_output()方法是基于run()方法实现的,因此接受大部分相同的参数。
- capture_output参数从Python 3.7版本开始可用,而不是3.5版本。
以上是关于如何使用Python的subprocess.Popen()来检测git命令hang住的原因和解决方法的整理。