How to create non-blocking continuous reading from `stdin`?

前端 未结 5 1602
小蘑菇
小蘑菇 2021-02-04 19:27

I have a single process, which has been created like this:

p = subprocess.Popen(args   = \'./myapp\',
                     stdin  = subprocess.PIPE,
                     


        
5条回答
  •  鱼传尺愫
    2021-02-04 19:49

    I've written a program that does... basically everything involving IO asynchronously. It reads input on a thread, it outputs on a thread, it creates a process, and it communicates with that process on a thread.

    I am not sure exactly what your program needs to accomplish, but hopefully this code accomplishes it.

    # Asynchronous cat program!
    
    # Asynchronously read stdin
    # Pump the results into a threadsafe queue
    # Asynchronously feed the contents to cat
    # Then catch the output from cat and print it
    # Thread all the things
    
    import subprocess
    import threading
    import queue
    import sys
    
    my_queue = queue.Queue()
    
    # Input!
    def input_method():
        for line in sys.stdin: # End on EOF
            if line == 'STOP\n': # Also end on STOP
                break
            my_queue.put(line)
    input_thread = threading.Thread(target=input_method)
    input_thread.start()
    
    print ('Input thread started')
    
    
    # Subprocess!
    cat_process = subprocess.Popen('cat', stdout=subprocess.PIPE, stdin=subprocess.PIPE)
    
    print ('cat process started')
    
    queue_alive = True
    # Continuously dump the queue into cat
    def queue_dump_method():
        while queue_alive:
            try:
                line = my_queue.get(timeout=2)
                cat_process.stdin.write(line.encode())
                cat_process.stdin.flush() # For some reason, we have to manually flush
                my_queue.task_done() # Needed?
            except queue.Empty:
                pass
    queue_dump_thread = threading.Thread(target = queue_dump_method)
    queue_dump_thread.start()
    
    print ('Queue dump thread started')
    
    # Output!
    def output_method():
        for line in cat_process.stdout:
            print(line)
    output_thread = threading.Thread(target=output_method)
    output_thread.start()
    
    print ('Output thread started')
    
    
    # input_thread will die when we type STOP
    input_thread.join()
    print ('Input thread joined')
    
    # Now we wait for the queue to finish processing
    my_queue.join()
    print ('Queue empty')
    
    queue_alive = False
    queue_dump_thread.join()
    print ("Queue dump thread joined")
    
    # Send EOF to cat
    cat_process.stdin.close()
    
    # This kills the cat
    cat_process.wait()
    print ('cat process done')
    
    # And make sure we're done outputting
    output_thread.join()
    print ('Output thread joined')
    

提交回复
热议问题