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

后端 未结 29 2592
醉酒成梦
醉酒成梦 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 05:01

    Existing solutions did not work for me (details below). What finally worked was to implement readline using read(1) (based on this answer). The latter does not block:

    from subprocess import Popen, PIPE
    from threading import Thread
    def process_output(myprocess): #output-consuming thread
        nextline = None
        buf = ''
        while True:
            #--- extract line using read(1)
            out = myprocess.stdout.read(1)
            if out == '' and myprocess.poll() != None: break
            if out != '':
                buf += out
                if out == '\n':
                    nextline = buf
                    buf = ''
            if not nextline: continue
            line = nextline
            nextline = None
    
            #--- do whatever you want with line here
            print 'Line is:', line
        myprocess.stdout.close()
    
    myprocess = Popen('myprogram.exe', stdout=PIPE) #output-producing process
    p1 = Thread(target=process_output, args=(dcmpid,)) #output-consuming thread
    p1.daemon = True
    p1.start()
    
    #--- do whatever here and then kill process and thread if needed
    if myprocess.poll() == None: #kill process; will automatically stop thread
        myprocess.kill()
        myprocess.wait()
    if p1 and p1.is_alive(): #wait for thread to finish
        p1.join()
    

    Why existing solutions did not work:

    1. Solutions that require readline (including the Queue based ones) always block. It is difficult (impossible?) to kill the thread that executes readline. It only gets killed when the process that created it finishes, but not when the output-producing process is killed.
    2. Mixing low-level fcntl with high-level readline calls may not work properly as anonnn has pointed out.
    3. Using select.poll() is neat, but doesn't work on Windows according to python docs.
    4. Using third-party libraries seems overkill for this task and adds additional dependencies.

提交回复
热议问题