如何创建一个超时后不会被kill的python子进程

在subprocess之前,创建一个新进程的方式有很多种,如os.system()、os.spawn*方法等。为了统一创建进程的方式,python社区提议使用subprocess模块作为创建进程的标准方式,用来替换os.system和os.spawn*等方式。

subprocess模块的使用

subprocess.run

方法签名如下

subprocess.run(*args*, *** , *stdin=None*, *input=None*, *stdout=None*, *stderr=None*, *capture_output=False*, *shell=False*, *cwd=None*, *timeout=None*, *check=False*, *encoding=None*, *errors=None*, *text=None*, *env=None*, *universal_newlines=None*, ***other_popen_kwargs*)

run方法是创建进程的推荐方法,只有run方法无法满足需要的时候才考虑使用popen方法。run会堵塞式地执行args参数提供的命令,直到命令执行结束或者超时。args可以是字符串数组或者字符串,当args为字符串时,shell参数必须为True。

我想创建一个子进程,使用adb install命令给vivo/oppo/xiaomi手机安装app,但是vivo/oppo/xiaomi手机会弹出二次确认窗口,如果不进行点击操作,则无法安装App。所以我就想创建一个子进程,超时后再接着由UI自动化的方式来点击确认按钮。这就要求超时后安装进程不能退出。run方法虽然有timeout参数,但是子进程会在超时被kill掉。

以下动画演示了手动安装app时需要二次确认,手动点击继续安装后,可以在控制台看到以下输出

Perform Streamed Install 
Success

证明已经安装成功了。


 

以下动画演示了使用run命令,超时后安装进程被kill掉了,在控制台无法看到成功安装的日志输出。二次确认后,安装进程就不见了。

对应的代码:

import subprocess

if __name__ == '__main__':

    proc=subprocess.run('adb install -g -r -t app-uiautomator.apk', shell=True, timeout=10, capture_output=True)

 

subprocess.Popen

subprocess模块里进程的创建和管理都是Popen类处理的,它让开发者非常灵活地处理一些不常见的场景。
 

-   *class* subprocess.Popen(*args*, *bufsize=- 1*, *executable=None*, *stdin=None*, *stdout=None*, *stderr=None*, *preexec_fn=None*, *close_fds=True*, *shell=False*, *cwd=None*, *env=None*, *universal_newlines=None*, *startupinfo=None*, *creationflags=0*, *restore_signals=True*, *start_new_session=False*, *pass_fds=()* , *** , *group=None*, *extra_groups=None*, *user=None*, *umask=- 1*, *encoding=None*, *errors=None*, *text=None*, *pipesize=- 1*, *process_group=None*)

Popen类有以下几个方法:

  • Popen.communicate

    Popen.communicate(*input=None*, *timeout=None*)

    communicate()返回一个元组(stdout_data, stderr_data),如果Popen指定了text模式,stdout_data将为字符串,否则为byte

  1. input 向标准输入发送信息
  2. timeout 如果进行在timeout指定的时间之内没有结束,则抛出一个TimeoutExpired异常,且进程不会被杀死

抛出异常后可以继续重新调用communicate()

* Popen.send_signal(signal) 向子进程发送信号

* Popen.terminate() 停止子进程

* Popen.poll() 检查进程是否结束,没有结束返回None,否则返回执行状态的数值

 Popen.wait(timeout=None*) 等待子进程执行结束,如果timeout指定的时间之后进程没有结束,则抛出TimeoutExpired

 在我的执行场景中,需要使用communicate方法,以下是使用Popen类调用adb命令安装app的动画展示,超时后,手动点击继续安装,app最终安装成功。

对应的代码如下:


import subprocess

from subprocess import TimeoutExpired
 

if __name__ == '__main__':

    try:

        proc=subprocess.Popen('adb install -g -r -t app-uiautomator.apk', shell=True, text=True, stdout=subprocess.PIPE)

        stdout,errs = proc.communicate(timeout=10)

        print(f'stdout1:{stdout}')

    except TimeoutExpired as te:

        print('timeout')

        stdout,errs = proc.communicate()

        print(f'stdout2:\n{stdout}')

这样的话,我的目的就达到了。

参考文档

后语

如果大家喜欢我写的文章,欢迎大家点赞、收藏、评论留言或者私信与我交流。

1 篇内容引用
1 声望
0 粉丝
0 条评论
推荐阅读
如何创建python 虚拟环境venv
venv是Python 3中的一个内置模块,它提供了一种创建Python虚拟环境的方法。虚拟环境是一种隔离Python环境的机制,它可以让我们在同一台机器上使用不同的Python解释器和库,而不会互相干扰。在Python 2中,可以使...

namedlock阅读 78

程序员英语学习指南
动机为什么程序员要学习英语?工作:我们每天接触的代码都是英文的、包括很多技术文档也是英文的学习:最新最前沿的技术最开始都是只有English版本就业:学好英语让你的就业范围扩大到全球,而不只限于国内目标读...

九旬6阅读 674

安卓逆向之破解某成人APP播放次数限制
某成人水果APP非VIP用户存在播放次数限制,每天只能播放3次。超过3次需要购买VIP。 由于过于贫穷,于是抽空,对其安卓APP进行了逆向分析,最终成功破解了其播放次数限制。

悖论3阅读 1.4k评论 3

封面图
这一次,解决Flutter Dialog的各种痛点!
4.0版本做了重大调整,迁移请参照: SmartDialog 3.x 迁移 4.0本文内容已更新,文中内容及其代码皆为4.0用法前言Q:你一生中闻过最臭的东西,是什么?A:我那早已腐烂的梦。兄弟萌!!!我又来了!这次,我能自信...

小呆呆6661阅读 3.5k

封面图
网易云音乐开源全链路埋点方案-曙光埋点(dawn)
网易云音乐开源了曙光埋点 dawn,一个跨多端的全链路埋点解决方案,旨在构造一个完美的数据理想国。曙光埋点创造性的提出了埋点虚拟树(VTree),并在此基础上实现了诸多能力,解决大前端侧埋点困难、精度差、不...

云音乐技术团队2阅读 366

封面图
uni-app中安卓包检查更新、新版本下载、下载进度条显示功能实现
如果想要做一个app的话,可以有很多种选择方案,uni-app是其中的一个性价比高一些(坑多一些)的方案。本文记录一下,uni-app打安卓包以后,需要检查并下载更新,且显示进度条的功能。

水冗水孚2阅读 769

Flutter 让你的Dialog脱胎换骨吧!(Attach,Dialog,Loading,Toast)
4.0版本做了重大调整,迁移请参照: SmartDialog 3.x 迁移 4.0本文内容已更新,文中内容及其代码皆为4.0用法前言Q:你一生中闻过最臭的东西,是什么?A:我那早已腐烂的梦。兄弟萌!!!我又来了!这次,我能自信...

小呆呆6662阅读 2.3k

封面图
1 声望
0 粉丝
宣传栏