A non-blocking read on a subprocess.PIPE in Python

后端 未结 29 2669
醉酒成梦
醉酒成梦 2020-11-21 04:49

I\'m using the subprocess module to start a subprocess and connect to its output stream (standard output). I want to be able to execute non-blocking reads on its standard ou

29条回答
  •  攒了一身酷
    2020-11-21 04:49

    Here is my code, used to catch every output from subprocess ASAP, including partial lines. It pumps at same time and stdout and stderr in almost correct order.

    Tested and correctly worked on Python 2.7 linux & windows.

    #!/usr/bin/python
    #
    # Runner with stdout/stderr catcher
    #
    from sys import argv
    from subprocess import Popen, PIPE
    import os, io
    from threading import Thread
    import Queue
    def __main__():
        if (len(argv) > 1) and (argv[-1] == "-sub-"):
            import time, sys
            print "Application runned!"
            time.sleep(2)
            print "Slept 2 second"
            time.sleep(1)
            print "Slept 1 additional second",
            time.sleep(2)
            sys.stderr.write("Stderr output after 5 seconds")
            print "Eol on stdin"
            sys.stderr.write("Eol on stderr\n")
            time.sleep(1)
            print "Wow, we have end of work!",
        else:
            os.environ["PYTHONUNBUFFERED"]="1"
            try:
                p = Popen( argv + ["-sub-"],
                           bufsize=0, # line-buffered
                           stdin=PIPE, stdout=PIPE, stderr=PIPE )
            except WindowsError, W:
                if W.winerror==193:
                    p = Popen( argv + ["-sub-"],
                               shell=True, # Try to run via shell
                               bufsize=0, # line-buffered
                               stdin=PIPE, stdout=PIPE, stderr=PIPE )
                else:
                    raise
            inp = Queue.Queue()
            sout = io.open(p.stdout.fileno(), 'rb', closefd=False)
            serr = io.open(p.stderr.fileno(), 'rb', closefd=False)
            def Pump(stream, category):
                queue = Queue.Queue()
                def rdr():
                    while True:
                        buf = stream.read1(8192)
                        if len(buf)>0:
                            queue.put( buf )
                        else:
                            queue.put( None )
                            return
                def clct():
                    active = True
                    while active:
                        r = queue.get()
                        try:
                            while True:
                                r1 = queue.get(timeout=0.005)
                                if r1 is None:
                                    active = False
                                    break
                                else:
                                    r += r1
                        except Queue.Empty:
                            pass
                        inp.put( (category, r) )
                for tgt in [rdr, clct]:
                    th = Thread(target=tgt)
                    th.setDaemon(True)
                    th.start()
            Pump(sout, 'stdout')
            Pump(serr, 'stderr')
    
            while p.poll() is None:
                # App still working
                try:
                    chan,line = inp.get(timeout = 1.0)
                    if chan=='stdout':
                        print "STDOUT>>", line, "

提交回复
热议问题