Interprocess communication woes
Nick Craig-Wood
nick at craig-wood.com
Thu Jul 19 04:30:03 EDT 2007
Murali <murali.dhanakoti at gmail.com> wrote:
> After some investigation, I found out that this problem had nothing to
> do with my GUI app not getting refreshed and I was able to reproduce
> this problem with normal python scripts. Here is one such script
>
> #File test.py
> from subprocess import Popen
> from subprocess import PIPE
> import sys
> if __name__ == '__main__':
> prog = sys.argv[1]
> proc = Popen(prog, shell = True, stdout = PIPE, bufsize = 0)
> out = proc.stdout
> while proc.poll() is None:
> print out.readline()
>
> Run this program as follows
> $ test.py "ping -c 10 www.google.com"
>
> Now, you would see the responses as if you just launched ping on the
> command line. Now, lets look at another program. Here is a simple C++
> program that prints numbers 1 to 10 at the passage of every second
> (sort of a stopwatch)
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <sys/time.h>
> main ( )
> {
> timeval t1, t2;
> gettimeofday(&t1, NULL);
> int prev = -1;
> int cur = 0;
> while (true)
> {
> gettimeofday(&t2,NULL);
> if(t2.tv_sec - t1.tv_sec > 10)
> break;
> else
> {
> cur = t2.tv_sec-t1.tv_sec;
> if (cur != prev)
> {
> printf("%d\r\n",cur);
> prev = cur;
> }
> }
> }
> }
>
> if you would build this program and call it lets say timer ($ g++ -o
> timer timer.cpp) and run it with our python script like this
>
> $python test.py "./timer"
>
> you would see that every time you run the program your results vary
> and on top of this the stdout of the timer program gets displayed all
> at once presumably when the timer program has completed execution.
>
> Why this discrepancy between the ping and timer programs? Is my
> test.py script correct? Is there a better or a preferred method for
> doing interprocess communication in Python.
Buffering is your problem.
If you add a fflush(stdout); after the printf(...); you'll find the
c++ program works as you expect.
It is just a fact of life of the C stdio system. If it is connected
to a terminal then it will turn off buffering. If it is connected
anything else (eg a pipe via subprocess) then it will buffer stuff as
you've seen.
So you can
a) modify the c++ prog to add fflush() in or use setvbuf()
b) use the pexpect module - http://pexpect.sourceforge.net/
c) use the pty module (unix only)
The pexpect module will connect to the subprogram with pseudo-ttys,
fooling the program, and the C library, into thinking that it is
speaking to a terminal and turn off buffering. Pexpect doesn't work
on windows.
The fact that ping works is because it uses fflush() - you can see
this if you "ltrace" it.
--
Nick Craig-Wood <nick at craig-wood.com> -- http://www.craig-wood.com/nick
More information about the Python-list
mailing list