zoukankan      html  css  js  c++  java
  • 使用subprocessm模块管理进程

     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
    0

    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
    0

    另外一种方式是采用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对象的一个方法,该方法会阻塞父进程,直到子进程完成。同时,因为数据都是缓存在内存中的,所以如果数据很大的时候不要使用这个方法。

  • 相关阅读:
    怎样处理人际关系中的矛盾
    如何处理人际关系
    Python包含以下函数:
    与他人有效沟通的小技巧
    沟通时容易出现的问题
    如何在工作中提升自己
    第十三周进度报告
    第十二周学习进度
    团队绩效管理
    软件对标分析
  • 原文地址:https://www.cnblogs.com/bdhk/p/7440556.html
Copyright © 2011-2022 走看看