美文网首页
Python Popen communicate() 和wait

Python Popen communicate() 和wait

作者: 徐德东 | 来源:发表于2018-06-14 15:56 被阅读0次

     之所以会纠结到这个问题上是因为发现在调用Popen的wait方法之后程序一直没有返回。google发现wait是有可能产生死锁的。为了把这个问题彻底弄清楚,搜索一些资料过来看看:

    看到别人的例子:

    今天遇到的一个问题。简单说就是,使用 subprocess 模块的 Popen 调用外部程序,如果 stdout 或 stderr 参数是 pipe,并且程序输出超过操作系统的 pipe size时,如果使用 Popen.wait() 方式等待程序结束获取返回值,会导致死锁,程序卡在 wait() 调用上。

    ulimit -a 看到的 pipe size 是 4KB,那只是每页的大小,查询得知 linux 默认的 pipe size 是 64KB

    看例子

    #!/usr/bin/env python

    # coding: utf-8

    import subprocess

    def test(size):

        print 'start'

        cmd = 'dd if=/dev/urandom bs=1 count=%d 2>/dev/null' % size

        p = subprocess.Popen(args=cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True)

        #p.communicate()

        p.wait()

        print 'end'

    # 64KB

    test(64 * 1024)

    # 64KB + 1B

    test(64 * 1024 + 1)

    首先测试输出为 64KB 大小的情况。使用 dd 产生了正好 64KB 的标准输出,由 subprocess.Popen 调用,然后使用 wait() 等待 dd 调用结束。可以看到正确的 start 和 end 输出;然后测试比 64KB 多的情况,这种情况下只输出了 start,也就是说程序执行卡在了 p.wait() 上,程序死锁。具体输出如下:

    start

    end

    start

    那死锁问题如何避免呢?官方文档里推荐使用 Popen.communicate()。这个方法会把输出放在内存,而不是管道里,所以这时候上限就和内存大小有关了,一般不会有问题。而且如果要获得程序返回值,可以在调用 Popen.communicate() 之后取 Popen.returncode 的值。

    结论:如果使用 subprocess.Popen,就不使用 Popen.wait(),而使用 Popen.communicate() 来等待外部程序执行结束。

    相关文章

      网友评论

          本文标题:Python Popen communicate() 和wait

          本文链接:https://www.haomeiwen.com/subject/vbuyeftx.html