subprocess被用来替换一些老的模块和函数,如:os.system、os.spawn*、os.popen*、popen2.*、commands.*。

subprocess的目的就是启动一个新的进程并且与之通信。

1.Popen

subprocess模块中只定义了一个类: Popen。可以使用Popen来创建进程,并与进程进行复杂的交互。它的构造函数如下:

subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)

其参数解释如下所示:

参数

说明

args

字符串或者列表

bufsize

0 无缓冲
1 行缓冲
其他正值 缓冲区大小
负值 采用默认系统缓冲(一般是全缓冲)

executable

一般不用吧,args字符串或列表第一项表示程序名

stdin
stdout
stderr

None 没有任何重定向,继承父进程
PIPE 创建管道
文件对象
文件描述符(整数)
stderr 还可以设置为 STDOUT

preexec_fn

钩子函数, 在fork和exec之间执行。(unix)

close_fds

unix 下执行新进程前是否关闭0/1/2之外的文件
windows下不继承还是继承父进程的文件描述符

shell

为真的话
unix下相当于args前面添加了 "/bin/sh“ ”-c”
window下,相当于添加"cmd.exe /c"

cwd

设置工作目录

env

设置环境变量

universal_newlines

各种换行符统一处理成 '\n'

startupinfo

window下传递给CreateProcess的结构体

creationflags

windows下,传递CREATE_NEW_CONSOLE创建自己的控制台窗口

(1)子进程的简单控制

例 1
#!/usr/bin/python3
import subprocess
pingP = subprocess.Popen(args='ping -n 4 www.baidu.com',shell=True)
print(pingP.pid)
print(pingP.returncode)

执行结果如下所示:

D:\workspace\Python\python3\practise\subprocess>python3 demo01.py
2356
None D:\workspace\Python\python3\practise\subprocess>
Pinging www.a.shifen.com [115.239.210.27] with 32 bytes of data:
Reply from 115.239.210.27: bytes=32 time=9ms TTL=57
Reply from 115.239.210.27: bytes=32 time=11ms TTL=57
Reply from 115.239.210.27: bytes=32 time=26ms TTL=57
Reply from 115.239.210.27: bytes=32 time=7ms TTL=57 Ping statistics for 115.239.210.27:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 7ms, Maximum = 26ms, Average = 13ms

从输出可以看出,代码生产了一个子进程并执行了args中指定的命令,然后执行下面的语句。由于网络应用的延迟,这就使得在打印出了进程ID和返回值后才输出外部命令的输出。

由于外部程序是在一个新生成的子程序中执行的,所以如果不加以限制,则有可能回将原进程和子进程的输出混淆。如果需要等待该子进程结束,可以使用Popen类中的wait()函数,如下面的代码所示:

例2
#!/usr/bin/python3
import subprocess
pingP = subprocess.Popen(args='ping -n 4 www.baidu.com',shell=True)
pingP.wait() #等待进程完成
print(pingP.pid)
print(pingP.returncode)

执行结果如下所示:

D:\workspace\Python\python3\practise\subprocess>python3 demo01.py

Pinging www.a.shifen.com [115.239.210.27] with 32 bytes of data:
Reply from 115.239.210.27: bytes=32 time=14ms TTL=57
Reply from 115.239.210.27: bytes=32 time=7ms TTL=57
Reply from 115.239.210.27: bytes=32 time=6ms TTL=57
Reply from 115.239.210.27: bytes=32 time=17ms TTL=57 Ping statistics for 115.239.210.27:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 6ms, Maximum = 17ms, Average = 11ms
18508

wait()函数将等待子进程的完成,将会返回子进程的返回值。

从上面的输出中可以看到,现在子进程的进程ID和返回值已经在子进程输出的后面了。同时,子进程的返回值已经变为0,表示子进程已经顺利退出。

此外,你还可以在父进程中对子进程进行其它操作,比如我们上面例子中的child对象:

pingP.poll() # 检查子进程状态
pingP.kill() # 终止子进程
pingP.send_signal() # 向子进程发送信号
pingP.terminate() # 终止子进程
ps: 子进程的PID存储在child.pid

(2) 子进程文本流控制

在上面的两个示例程序中,子进程被创建后,其标准输入、标准输出和标准错误处理都和原进程没有关系。如果要管理子进程的输入输出,可以改变Popen类中的stdin、stdout和stderr等类参数。如何使用以前的进程创建方法,则需要将输入输出重定向。

例 3
#!/usr/bin/python3
import subprocess pingP = subprocess.Popen(args='ping -n 4 www.baidu.com',shell=True,stdout = subprocess.PIPE)
pingP.wait()
print(pingP.stdout.read()) #读取进程的输出信息,
print(pingP.pid)
print(pingP.returncode)

代码说明:

  • 在Popen的类参数中,stdin、stdout、stderr分别用来指定程序标准输入、标准输出和标准错误的处理器,其值可以为PIPE、文件描述符和None等。默认值都为None。
  • 在获取输出后,pingP.stdout(<open file '<fdopen>',mode 'rb'>)成为一个可读的文件对象,可以使用相应的文件操作函数来读取。

单单从输出来看,例2和例3的输出是一样的。但是,两者是完全不同的。在例2中,子进程的输出并没有得到控制。而在例3中,其子进程的输出则被收集起来了。如果将脚本中的“print(pingP.stdout.read())”这句注释掉,则程序输出如下:

D:\workspace\Python\python3\practise\subprocess>python3 demo01.py
15404

另外一种方式是采用Popen类提供的communicate方法。示例如下

#!/usr/bin/env python
import subprocess ch1 = subprocess.Popen(['cat','/etc/passwd'],stdout=subprocess.PIPE)
ch2 = subprocess.Popen(['grep','root'],stdin=ch1.stdout,stdout=subprocess.PIPE) res = ch2.communicate()
print(res)

输出结果为:

('root:x:0:0:root:/root:/bin/bash\n', None)

subprocess.PIPE实际上为文本流提供一个缓存区。ch1的stdout将文本输出到缓存区,随后ch2的stdin从该PIPE中将文本读取走。ch2的输出文本也被存放在PIPE中,直到communicate()方法从PIPE中读取出PIPE中的文本。

communicate()方法返回的是一个(stdout,sterr)元组。需要注意的是,communicate()是Popen对象的一个方法,该方法会阻塞父进程,直到子进程完成。同时,因为数据都是缓存在内存中的,所以如果数据很大的时候不要使用这个方法。

使用subprocessm模块管理进程的更多相关文章

  1. Supervisord管理进程实践

    今天凑空研究了下Supervisord,这是一款linux进程管理工具,使用python开发,主要用于在后台维护进程(类似master守护进程),可以实现监控进程的状态.自动重启进程等操作,便于一些服 ...

  2. 解析Linux内核的基本的模块管理与时间管理操作---超时处理【转】

    转自:http://www.jb51.net/article/79960.htm 这篇文章主要介绍了Linux内核的基本的模块管理与时间管理操作,包括模块加载卸载函数的使用和定时器的用法等知识,需要的 ...

  3. 使用multiprocessing模块操作进程

    1.Process模块介绍 process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建. Process([group [, target [, name [, args [, kwa ...

  4. MVC4做网站后台:模块管理1、修改模块信息

    网站可能会包含一些模块:像文章.产品.图片.留言等. 栏目模块主要实现功能,启用或禁用模块,模块权限设置,模块上传设置等. 权限设置和上传设置以后专门考虑,先来显示或禁用模块. 1.在顶部导航栏添加管 ...

  5. 基于吉日嘎底层架构的Web端权限管理操作演示-菜单模块管理

    按照顺序,这一篇介绍菜单模块管理,主要演示如下操作: 新增.修改.锁定.解锁.删除.撤销删除 排序 角色成员管理 用户成员管理 导出菜单模块数据 也许你会问,你在这自吹自擂,你这个BS的权限管理有啥缺 ...

  6. JS模块规范 前端模块管理器

    一:JS模块规范(为了将js文件像java类一样被import和使用而定义为模块, 组织js文件,实现良好的文件层次结构.调用结构) A:CommonJS就是为JS的表现来制定规范,因为js没有模块的 ...

  7. 【转】Nginx系列(三)--管理进程、多工作进程设计

    原博文出于:http://blog.csdn.net/liutengteng130/article/details/46700999  感谢! Nginx由一个master进程和多个worker进程组 ...

  8. 关于html5 -- plus Webview模块管理应用窗口界面

    Webview模块管理应用窗口界面,通过plus.webview可获取应用界面管理对象. 方法: all:获取所有的webview窗口 close:关闭webview窗口 create:创建新的web ...

  9. python模块管理

    参考python的模块管理,请看如下 http://blog.sina.com.cn/s/blog_90bc5fc6010159e0.html http://hi.baidu.com/billsche ...

随机推荐

  1. Delphi 2010 中的泛型

    Delphi 2010 中的泛型 2010已发布很长时间了,口碑还不错,准备用它开发下一项目,但对泛型等新东西的认识还不够,就搜了一下,发现下面这篇文章,还不错,大家一起补补课吧! C++中的模板.C ...

  2. 顺时针打印矩阵元素(python实现)

    我觉得我的算法比较简单易懂,比网上的那些简单些.至于时间复杂度就没有比较了. 算法思想:从最外层向内层遍历矩阵 # my algorithmimport math def print_matrix(m ...

  3. spark2.+ sql 性能调优

    1.在内存中缓存数据 性能调优主要是将数据放入内存中操作,spark缓存注册表的方法 版本 缓存 释放缓存 spark2.+ spark.catalog.cacheTable("tableN ...

  4. 面试39 MySQL读写分离

    (1)如何实现mysql的读写分离? 其实很简单,就是基于主从复制架构,简单来说,就搞一个主库,挂多个从库,然后我们就单单只是写主库,然后主库会自动把数据给同步到从库上去. (2)MySQL主从复制原 ...

  5. Window下,前后端分离项目,登录权限验证中的,Redis相关操作

    [1]官网下载Redis(解压版) https://redis.io/download [2]切换到目录下打开DOS,执行指令启动Redis redis-server.exe redis.window ...

  6. 为kubectl配置别名和命令行补齐

    配置别名 # vim ~/.bashrc 添加 alias k='kubectl' # source ~/.bashrc 配置命令行补齐 # yum install -y bash-completio ...

  7. HTTP入门简介

    一.概念:Hyper Text Transfer Protocol 超文本传输协议 传输协议:定义了客户端和服务器端通信时,发送数据的格式 特点: 1.基于TCP/IP的高级协议 2.默认端口号:80 ...

  8. 关于js私钥加密公钥解密的问题

    博客荒废很久了,最近遇到一个问题,看网上的说明比较少,所以写下来给大家一个参考 一般来说rsa算法都是使用公钥加密,私钥解密,或者私钥签名,公钥验签.但总有特别的时候会想要用私钥加密,公钥解密,但是j ...

  9. 2019-8-31-C#-如何写出一个不能被其他程序集继承的抽象类

    title author date CreateTime categories C# 如何写出一个不能被其他程序集继承的抽象类 lindexi 2019-08-31 16:55:58 +0800 20 ...

  10. adb命令 logcat日志抓取

    一.logcat抓log方法:adb logcat命令,可以加条件过滤 1.安装SDK(参考android sdk环境安装) 2.使用数据线链接手机,在手机助手的sdcard中建立一个1.log的文件 ...