Python: Select() Doesn't Signal All Input From Pipe
I am trying to load an external command line program with Python and communicate with it via pipes. The progam takes text input via stdin and produces text output in lines to stdou
Solution 1:
Note that internally file.readlines([size])
loops and invokes the read()
syscall more than once, attempting to fill an internal buffer of size
. The first call to read()
will immediately return, since select() indicated the fd was readable. However the 2nd call will block until data is available, which defeats the purpose of using select. In any case it is tricky to use file.readlines([size])
in an asynchronous app.
You should call os.read(fd, size)
once on each fd for every pass through select. This performs a non-blocking read, and lets you buffer partial lines until data is available and detects EOF unambiguously.
I modified your code to illustrate using os.read
. It also reads from the process' stderr
:
import os
import select
import subprocess
from cStringIO import StringIO
target = 'Engine'
PIPE = subprocess.PIPE
engine = subprocess.Popen(target, bufsize=0, stdin=PIPE, stdout=PIPE, stderr=PIPE)
engine.stdin.write(b"go\n")
engine.stdin.flush()
class LineReader(object):
def __init__(self, fd):
self._fd = fd
self._buf = ''
def fileno(self):
returnself._fd
def readlines(self):
data = os.read(self._fd, 4096)
ifnot data:
# EOF
return None
self._buf += data
if'\n'notin data:
return []
tmp = self._buf.split('\n')
lines, self._buf = tmp[:-1], tmp[-1]
returnlines
proc_stdout = LineReader(engine.stdout.fileno())
proc_stderr = LineReader(engine.stderr.fileno())
readable = [proc_stdout, proc_stderr]
while readable:
ready = select.select(readable, [], [], 10.0)[0]
ifnot ready:
continue
for stream in ready:
lines = stream.readlines()
iflines is None:
# got EOF on this stream
readable.remove(stream)
continue
for line inlines:
print line
Post a Comment for "Python: Select() Doesn't Signal All Input From Pipe"