zoukankan      html  css  js  c++  java
  • 使用subprocess.Poen注意事项

     学习使用python已经有四个月了,subprocess这个执行linux中shell命令的函数已经用过无数次了,踩到的坑也有几个,写出来分享一下,欢迎大家拍砖头。

    1.shell命令中若有管道,一定要多次调用Poen,p1的输出当作p2的输入。
        例如:shell命令

    hdfs dfs -cat test.log.lzo | lzop -d | head -n 2 

        此命令可以查看hdfs上面一个lzo文件中的前两行,开始没有看subprocess的手册,直接代码就写成:

    shell_comm="hdfs dfs -cat test.log.lzo | lzop -d | head -n 2"
    outPipe=subprocess.Popen(shell_comm,shell=True,stdout=subprocess.PIPE)

        结果输出那是一堆乱码,纠结了半天,一直以为是编码不统一的问题,找了N久,郁闷良久,最后老大跟我说,subprocess不是这样用的,管道必须使用多个popen,代码改成:

    comm1="hdfs dfs -cat test.log.lzo"
    comm2="lzop -d"
    comm3="head -n 2"
    p1=subprocess.Popen(comm1,shell=True,stdout=subprocess.PIPE)
    p2=subprocess.Popen(comm2,shell=True,stdoin=p1.stdout,stdout=subprocess.PIPE)
    p3=subprocess.Popen(comm3,shell=True,stdoin=p2.stdout,stdout=subprocess.PIPE)

        最后p3的输出就是你想要的结果了

    2.python2.7多个管道连接输出会出现Broken pipe提示。

        像上面代码中多个管道连续输出,最后p3却只取前2行,comm1|2在一直不停的执行,comm3却终止了,此时就会出现Broken pipe提示,这是python的一个bug,具体原因和解决办法可见http://bugs.python.org/issue1652   https://code.google.com/p/python-subprocess32/

    3.subprocess一定要收集子进程状态

        这就牵扯到我写代码过程中跳的一个坑,看网上写的使用subprocess的例子,都是直接执行命令,然后读取PIPE内容,我也照做,根本没有想到收集什么进程状态这回事。有一天,老大把我叫过去,看着我说:“我发现一个问题,为什么每次你写的这个程序运行起来,服务器内存使用量一下子就上升了2、3十G?”

        经过各种traceback和lsof查看进程状态,发现罪魁祸首居然是subprocess,最重要的是我调用了subprocess.Popen之后没有收集子进程状态。我的整个程序运行了5、6分钟,打开了hdfs上的上百个文件,而且都是取开头两行,开启了N个子进程,都没有收集,那么这些子进程的数据全部都算在了程序主进程中,一直占用服务器内存,并且越堆积越多。最后加上状态收集语句之后问题解决。

    4.subprocess.wait()与subprocess.communicate()使用问题

        subprocess就是开启一个子进程,自己去执行命令,这个子进程的状态肯定得收集,这时候就需要调用wait或者communicate了,手册上面也注明了这两个方法的特点:在数据超过PIPE的缓存时,wait会阻塞进程;communicate会把所有的数据都读取到内存中。
    wait:

    Warning
    This will deadlock if the child process generates enough output to a stdout or stderr pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that.

    communicate:

    Note
    The data read is buffered in memory, so do not use this method if the data size is large or unlimited

        那么现在就有一个问题了,当我shell命令执行的结果很大时,我是该用wait还是communicate?用wait直接就阻塞了,肯定不行,用communicate也不行,如果很大的文件,数据都保存在内存,主机直接就卡死了。

        解决办法:数据一行一行读取,读取完之后wait,这样既保证了不会阻塞(PIPE中数据有进有出,最后空了才wait),又保证了不会占用大量主机内存(在内存中的数据只有一行line)。

    p1=subprocess.Popen(comm1,shell=True,stdout=subprocess.PIPE)
    for line in p1.stdout:
        pass
    p1.wait()
  • 相关阅读:
    layui 3种导航栏
    SQL语句内做除法得出百分比
    JS 日期比较方法
    JDK 13 的 12 个新特性,真心涨姿势了
    怎么实现单点登录?面试必问!
    厉害了,Apache架构师们遵循的 30 条设计原则
    面试官问线程安全的List,看完再也不怕了!
    Java 类在 Tomcat 中是如何加载的?
    Redis 21问,你接得住不?
    String hashCode 这个数字,很多人不知道!
  • 原文地址:https://www.cnblogs.com/havePassed/p/4950751.html
Copyright © 2011-2022 走看看