• Python 中的线程与进程(二)


    使用 subprocess 模块管理进程

      上篇针对进程的创建和终止做了一些说明,但是,这些仅仅是基本的进程管理函数,无法满足复杂的需求。因此,Python提供了subporcess模块进程高级的进程管理。subprocess可以调用外部的系统命令创建新的子进程,同时连接到子进程的input/output/error管道上,并得到子进程的返回值。subprocess模块中提供了一个类和两个实用函数来管理进程,下面进行分别介绍

    1 使用Popen类管理进程

      subprocess模块中高级进程的管理能力来自于Popen来的灵活使用,这源于该类中函数原型的丰富参数。

    class 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参数为要执行的外部程序。其值可以使字符串或者序列。除此之外,其他的类参数都有默认值,可以根据需要进行修改。

      例子:演示使用Popen类的方法

    import subporcess
    
    pingP = subprocess.Popen(args = 'ping -c 4 www.sina.com.cn', shell = True)
    pingP.wait()
    print pingP.pid
    print pingP.returncode


    root@wpeng-desktop:/# python sh02.py PING cernetnews.sina.com.cn (121.194.0.239) 56(84) bytes of data. 64 bytes from 121.194.0.239: icmp_seq=1 ttl=52 time=2.43 ms 64 bytes from 121.194.0.239: icmp_seq=2 ttl=52 time=1.00 ms 64 bytes from 121.194.0.239: icmp_seq=3 ttl=52 time=1.48 ms 64 bytes from 121.194.0.239: icmp_seq=4 ttl=52 time=1.02 ms --- cernetnews.sina.com.cn ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 15036ms rtt min/avg/max/mdev = 1.001/1.486/2.439/0.583 ms 2230 0

      上面是程序代码和我电脑的输出,代码中Popen的第二个参数为shell的值。在Linux下,当shell为“False“时,Popen会调用os.execvp来执行对应的程序,而shell为True时,如果命令为字符串,Popen直接调用系统shell来执行指定的程序。如果命令是一个序列,则其第一项是定义命令字符串,其他项为命令的附加参数。

      从输出可以看出,代码产生一个子进程并执行args中指定的命令,然后继续执行下面的语句。如果上面代码不加pingP.wait(),由于网络延迟,会使得在打印了进程ID和返回值后才输出外部命令的结果。

    root@wpeng-desktop:/# python sh02.py
    2247
    None
    root@wpeng-desktop:/# PING cernetnews.sina.com.cn (121.194.0.239) 56(84) bytes of data.
    64 bytes from 121.194.0.239: icmp_seq=1 ttl=52 time=1.17 ms
    64 bytes from 121.194.0.239: icmp_seq=2 ttl=52 time=1.02 ms
    64 bytes from 121.194.0.239: icmp_seq=3 ttl=52 time=1.13 ms
    64 bytes from 121.194.0.239: icmp_seq=4 ttl=52 time=0.899 ms
    
    --- cernetnews.sina.com.cn ping statistics ---
    4 packets transmitted, 4 received, 0% packet loss, time 15029ms
    rtt min/avg/max/mdev = 0.899/1.058/1.173/0.107 ms

      上面None表示次子进程还没有终止。

      子进程创建以后其标准输出 标准输入 标准错误处理都和原进程没有关系。如果需要管理子进程的输入和输出,可以改变Popen类中的stdin stdout stderr等类的参数。在Popen的类参数中,stdin stdout stderr分别用来指定程序标准输入 标准输出和标准错误的处理器,其值可以为‘PIPE‘,文件描述符和'None'等,默认是“None“

    import subporcess
    
    pingP = subprocess.Popen(args = 'ping -c 4 www.sina.com.cn', shell = True, stdout = subprocess.PIPE)
    pingP.wait()
    print pingP.stdout.read()
    print pingP.pid
    print pingP.returncode

      在获取输出结果后,pingP.stdout成为一个可读的文件对象,可以使用相应的文件操作函数来读取。

      虽然上面代码和第一个代码输出相同,但是如果你把print pingP.stdout.read()用#注释掉,会发现不同之处,不妨试试把~

    root@wpeng-desktop:/# python sh02.py
    2273
    0

        另一种方法时使用Popen提供的communicate方法,该方法为p.communicate([input]),通过将input中提供的数据发送给进程的标准输入,与子进程进行通信。数据一旦发送,方法就会等待进程终止,同时收集标准输出上接收到的输出和标准错误。返回值是一个元组(stdout,stderr)。

      子进程的文本流控制

        子进程的标准输入,标准输出和标准错误也可以通过如下属性表示:

    pingP.stin
    pingP.stdout
    pingP.stderr

     

    我们可以在Popen()建立子进程的时候改变标准输入、标准输出和标准错误,并可以利用subprocess.PIPE将多个子进程的输入和输出连接在一起,构成管道(pipe):

    import subprocess
    child1 = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE)
    child2 = subprocess.Popen(["wc"], stdin=child1.stdout,stdout=subprocess.PIPE)
    print child2.stdout.read()

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

    要注意的是,communicate()是Popen对象的一个方法,该方法会阻塞父进程,直到子进程完成。

     

    我们还可以利用communicate()方法来使用PIPE给子进程输入:

    import subprocess
    child = subprocess.Popen(["cat"], stdin=subprocess.PIPE)
    child.communicate("bupt")

    我们启动子进程之后,cat会等待输入,直到我们用communicate()输入"vamei"。

     

    通过使用subprocess包,我们可以运行外部程序。这极大的拓展了Python的功能。如果你已经了解了操作系统的某些应用,你可以从Python中直接调用该应用(而不是完全依赖Python),并将应用的结果输出给Python,并让Python继续处理。shell的功能(比如利用文本流连接各个应用),就可以在Python中实现。

    2  调用外部系统命令

      subprocess还提供两个使用函数用来直接调用外部系统命令:call(), check_all()。两者是对上面Popen类构造函数使用方法的简化。其参数列表和Popen构造函数的参数列表是一样的。call会直接调用命令生成子进程,并且等待子进程结束,然后返回子进程的返回值。如果要执行一个命令,但又不需要捕捉他的输入或者以其他方式控制它,可以调用这个函数。check_all和call最大的区别是:如果返回值不为0,出发CallProcessError异常,返回值保存在这个异常对象的returncode属性中。

    3  Popen()函数返回的Popen对象p具有的一些方法和属性

    p.kill()p.communication([input])
    p.send_signal(signal)
    p.poll()
    p.wait()
    p.pid()
    p.terminate()
    p.returncode()
    p.stdin, p.stdout, p.stderr

    总结:

    subprocess.Popen()
    Popen.wait()
    subprocess.PIPE
    Popen.communicate()subprocess.call()
    subprocess.check_all()

    有个不错的文章推荐一下: http://www.cnblogs.com/vamei/archive/2012/09/23/2698014.html

  • 相关阅读:
    sql 大数据量 的分表操作
    NHibernate 2.0 配置
    NHibernate 之调用存储过程
    k-v-o 扫盲
    320学习笔记 2
    GCD之dispatch queue
    使用KVO体会
    timer,runloop,thread,task小总结
    Run Loop
    iPh oto的删除动画
  • 原文地址:https://www.cnblogs.com/bupt/p/sh02.html
Copyright © 2020-2023  润新知