Python2.7下,调用subprocess启动子进程,读取子进程标准输出若干问题

1:如果调用的子进程也是一个python脚本,则subprocess.Popen中的bufsize=1无效果。也就是说,即使设置了bufsize=1表示进行行缓冲,子进程如果不显示调用sys.stdout.flush,父进程依然会阻塞在readline上:

#testbuf.py 
import subprocess cmd = "./testsub.sh" cmd2 = ["python", "testsub.py"] sp = subprocess.Popen(cmd2, bufsize = 1, stdout = subprocess.PIPE) while True: line = sp.stdout.readline() print 'read line is ', line if not line: break

 

testsub.py代码如下:

import time
import sys

for i in range(100000):
        print 'hello, world', i
        #sys.stdout.flush()
        time.sleep(1)

 

执行testbuf.py脚本,该脚本将会阻塞在sp.stdout.readline()上,除非将子进程testsub杀掉,否则,该脚本将会长时间阻塞在这条语句上。

如果将testsub.py中的sys.stdout.flush()前注释去掉,则父进程可以得到正常的输出。

 

如果执行的是shell脚本testsub.sh,则没有这种问题,该脚本代码如下:

#!/bin/bash

for((i=1;i<=10000000;i++));
do 
        echo “hello, world”, $i
        sleep 1
done

 

 

2:如果子进程是一个长时间运行的程序,而父进程想以行为单位实时读取子进程的输出,则父进程不能以for line in sp.stdout的形式读取子进程输出:

#testbuf.py 

import subprocess

cmd = "./testsub.sh"
cmd2 = ["python", "testsub.py"]
sp = subprocess.Popen(cmd2, bufsize = 1, stdout = subprocess.PIPE)

for line in sp.stdout:
        print 'read line is ', line
        if not line: break

 

这种情况下,进程阻塞在for line in sp.stdout上。这实际上是python2的一个bug:

https://bugs.python.org/issue3907

https://stackoverflow.com/questions/2804543/read-subprocess-stdout-line-by-line

https://ubuntuforums.org/showthread.php?t=916518

这个bug在python3中据说解决了,但是在python2下,还是不可以用for line in sp.stdout这种形式。可以使用readline:

for line in iter(proc.stdout.readline,''):
    print line

 

 

3:如果子进程有大量输出,而父进程调用subprocess.Popen时又设置了stdout = subprocess.PIPE,并且没有及时读取stdout中的内容,则一旦缓冲区满了(缓冲区默认大小为65535),则子进程会在写入标准输出时hang住。

 

posted @ 2017-12-19 11:47  gqtc  阅读(942)  评论(0编辑  收藏  举报