Force another program's standard output to be unbuffered using Python
A python script is controlling an external application on Linux, passing in input via a pipe to the external applications stdin, and reading output via a pipe from the external applications stdout.
The problem is that writes to pipes are buffered by block, and not by line, and therefore delays occur before the controlling script receives data output by, for example, printf in the external application.
The external application cannot be alte开发者_如何学编程red to add explicit fflush(0) calls.
How can the pty module of the python standard library be used with the subprocess module to achieve this?
You can use PTYs to solve this by:
- Creating a pty master/slave pair;
- Connecting the child process's stdin, stdout and stderr to the pty slave device;
- Reading from and writing to the pty master in the parent.
Doing this is possible, but the only solution I can think of is fairly convoluted, non-portable, and probably fraught with problematic details. You can use LD_PRELOAD to cause the external application to load a dynamic library which contains a constructor that invokes setvbuf to unbuffer stdout. You will probably also want to wrap setvbuf in the library to prevent the application from explicitly buffering its own stdout. And you'll want to wrap fwrite and printf so that they flush on each call. Writing the .so to be preloaded will take you outside of python.
I don't think it's possible. If the source application doesn't flush its outgoing buffer, the data will not reach outside that process until the buffer overflows and a flush is forced.
Notice how a well-established command such as file has an option (-n) that causes it to flush its output explicitly. This is required when using file in the mode where it reads input file names from a pipe, and prints the detected type. Since in this mode, the file program doesn't quit when done, the output would otherwise not appear.
Consider this at a lower level: the output buffering simply means that doing write()
on a buffered stream copies the data into an in-memory buffer, until the buffer fills up or (typically) until a linefeed is found. Then, the part of the buffer up to the overflow or linefeed is written write()
n to the underlying system-level file descriptor (which could be a file, a pipe, a socket, ...).
I don't understand how you're going to convince that program to flush its buffer, from the outside.
Its worth noting that some programs only buffer their output when they think it's not going to a "real user" (ie, a tty). When they detect that their output is being read by another program, they buffer.
The emulation of a tty is one of the things that Expect does in automating other processes.
There is a pure Python implementation of Expect, but I don't know how well it handles tty emulation.
The answer to this question might help:
Python Run a daemon sub-process & read stdout
Seems to be addressing the same issue.
This question is a bit old, but I think your problem could now be solved by using subprocess to call stdbuf with the command you want to exec.
Try running the Python interpreter with the -u argument:
python -u myscript.py
This forces Python to use unbuffered stdin/stdout which may help you.
精彩评论