In the application I am developing I have a thread that when initialized starts a suprocess by Popen redirecting the stdout to PIPE. In the run() I need to wait both on the pipe and on an event.
The output of the pipe must be outputted on a textview.
When the event is set the thread must stop returning from the run().
My solution is to
- wait on the pipe by a timeouted select.select
- then if the select returns the pipe is readable
- read a single byte from the pipe, so I am sure this reading can't block
- store the byte in a bytearray up to I receive a newline
- output the bytearray to a textviev
 
 
- testing the event
This works but reading 1 byte per time is really inefficient
I am wondering it a more efficient solutions exists.
This is a snippet of my code:
class ProcessEcho(threading.Thread):
    def __init__(self,environ,command_line,textbuffer,on_process_exited_cb):
        super(ProcessEcho,self).__init__()
        self.textbuffer = textbuffer
        self.on_process_exited_cb = on_process_exited_cb
        self.popen = subprocess.Popen(command_line,stdout = subprocess.PIPE, stderr = subprocess.STDOUT,bufsize=0,env=environ)
        self.exit_event = threading.Event()
        self.daemon = True
        self.start()
    def get_pid(self):
        return self.popen.pid
    def stop(self):
        self.exit_event.set()
    def update_textbuffer(self,string):
        self.textbuffer.insert(self.textbuffer.get_end_iter(),string)
    def run(self):
        buffer = bytearray()
        while True:
            rl,wl,xl = select.select([self.popen.stdout], [], [], 1)
            if len(rl):
                r = self.popen.stdout.read(1)
                if r=='':
                    self.popen.communicate()
                    GObject.idle_add(self.on_process_exited_cb)
                    return
                else:
                    buffer.append(r)
                    if r == "\n":
                        GObject.idle_add(self.update_textbuffer,str(buffer))
                        buffer = bytearray()
            if self.exit_event.is_set():
                self.popen.communicate()
                GObject.idle_add(self.on_process_exited_cb)
                return
 
    