I'm using the subprocess module to start a subprocess and connect to it's output stream (stdout). I want to be able to execute non-blocking reads on its stdout. Is there a way to make .readline non-blocking or to check if there is data on the stream before I invoke .readline
? I'd like this to be portable or at least work under Windows and Linux.
here is how I do it for now (It's blocking on the .readline
if no data is avaible):
p = subprocess.Popen('myprogram.exe', stdout = subprocess.PIPE)
output_str = p.stdout.readline()
Python 3.4 introduces new provisional API for asynchronous IO --
asyncio
module.The approach is similar to
twisted
-based answer by @Bryan Ward -- define a protocol and its methods are called as soon as data is ready:See "Subprocess" in the docs.
There is a high-level interface
asyncio.create_subprocess_exec()
that returnsProcess
objects that allows to read a line asynchroniosly usingStreamReader.readline()
coroutine (withasync
/await
Python 3.5+ syntax):readline_and_kill()
performs the following tasks:Each step could be limited by timeout seconds if necessary.
Try the asyncproc module. For example:
The module takes care of all the threading as suggested by S.Lott.
This solution uses the
select
module to "read any available data" from an IO stream. This function blocks initially until data is available, but then reads only the data that is available and doesn't block further.Given the fact that it uses the
select
module, this only works on Unix.The code is fully PEP8-compliant.
I have often had a similar problem; Python programs I write frequently need to have the ability to execute some primary functionality while simultaneously accepting user input from the command line (stdin). Simply putting the user input handling functionality in another thread doesn't solve the problem because
readline()
blocks and has no timeout. If the primary functionality is complete and there is no longer any need to wait for further user input I typically want my program to exit, but it can't becausereadline()
is still blocking in the other thread waiting for a line. A solution I have found to this problem is to make stdin a non-blocking file using the fcntl module:In my opinion this is a bit cleaner than using the select or signal modules to solve this problem but then again it only works on UNIX...
I have the original questioner's problem, but did not wish to invoke threads. I mixed Jesse's solution with a direct read() from the pipe, and my own buffer-handler for line reads (however, my sub-process - ping - always wrote full lines < a system page size). I avoid busy-waiting by only reading in a gobject-registered io watch. These days I usually run code within a gobject MainLoop to avoid threads.
The watcher is
And the main program sets up a ping and then calls gobject mail loop.
Any other work is attached to callbacks in gobject.
fcntl
,select
,asyncproc
won't help in this case.A reliable way to read a stream without blocking regardless of operating system is to use
Queue.get_nowait()
: