472,967 Members | 1,939 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,967 software developers and data experts.

subprocess and non-blocking IO (again)

I am trying to rewrite a PERL automation which started a "monitoring"
application on many machines, via RSH, and then multiplexed their
collective outputs to stdout.

In production there are lots of these subprocesses but here is a
simplified example what I have so far (python n00b alert!)
- SNIP ---------
import subprocess,select,sys

speakers=[]
lProc=[]

for machine in ['box1','box2','box3']:
p = subprocess.Popen( ('echo '+machine+';sleep 2;echo goodbye;sleep
2;echo cruel;sleep 2;echo world'), stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stdin=None, universal_newlines=True )
lProc.append( p )
speakers.append( p.stdout )

while speakers:
speaking = select.select( speakers, [], [], 1000 )[0]
for speaker in speaking:
speech = speaker.readlines()
if speech:
for sentence in speech:
print sentence.rstrip('\n')
sys.stdout.flush() # sanity check
else: # EOF
speakers.remove( speaker )
- SNIP ---------
The problem with the above is that the subprocess buffers all its output
when used like this and, hence, this automation is not informing me of
much :)

In PERL, "realtime" feedback was provided by setting the following:
$p->stdout->blocking(0);

How do I achieve this in Python ?

This topic seems to have come up more than once. I am hoping that
things have moved on from posts like this:
http://groups.google.com/group/comp....4fa9b471009ab2
as I don't really want to have to write all that ugly
fork/dup/fcntl/exec code to achieve this when high-level libraries like
"subprocess" really should have corresponding methods.

If it makes anything simpler, I only *need* this on Linux/Unix (Windows
would be a nice extra though).

thanks for reading,
Marc
Oct 10 '05 #1
4 3331
In article <43********@news3.prserv.net>,
Marc Carter <mc*****@uk.ibm.com> wrote:
I am trying to rewrite a PERL automation which started a "monitoring"
application on many machines, via RSH, and then multiplexed their
collective outputs to stdout.

In production there are lots of these subprocesses but here is a
simplified example what I have so far (python n00b alert!)
- SNIP ---------
import subprocess,select,sys

speakers=[]
lProc=[]

for machine in ['box1','box2','box3']:
p = subprocess.Popen( ('echo '+machine+';sleep 2;echo goodbye;sleep
2;echo cruel;sleep 2;echo world'), stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stdin=None, universal_newlines=True )
lProc.append( p )
speakers.append( p.stdout )

while speakers:
speaking = select.select( speakers, [], [], 1000 )[0]
for speaker in speaking:
speech = speaker.readlines()
if speech:
for sentence in speech:
print sentence.rstrip('\n')
sys.stdout.flush() # sanity check
else: # EOF
speakers.remove( speaker )
- SNIP ---------
The problem with the above is that the subprocess buffers all its output
when used like this and, hence, this automation is not informing me of
much :)
You're using C stdio, through the Python fileobject. This is
sort of subprocess' fault, for returning a fileobject in the
first place, but in any case you can expect your input to be
buffered. You're asking for it, because that's what C stdio does.
When you call readlines(), you're further guaranteeing that you
won't go on to the next statement until the fork dies and its
pipe closes, because that's what readlines() does -- returns
_all_ lines of output.

If you want to use select(), don't use the fileobject
functions. Use os.read() to read data from the pipe's file
descriptor (p.stdout.fileno().) This is how you avoid the
buffering.
This topic seems to have come up more than once. I am hoping that
things have moved on from posts like this:
http://groups.google.com/group/comp....read/5472ce95e
b430002/434fa9b471009ab2?q=blocking&rnum=4#434fa9b471009ab 2
as I don't really want to have to write all that ugly
fork/dup/fcntl/exec code to achieve this when high-level libraries like
"subprocess" really should have corresponding methods.


subprocess doesn't have pty functionality. It's hard to say
for sure who said what in that page, after the incredible mess
Google has made of their USENET archives, but I believe that's
why you see dup2 there - the author is using a pty library,
evidently pexpect. As far as I know, things have not moved on
in this respect, not sure what kind of movement you expected
to see in the intervening month. I don't think you need ptys,
though, so I wouldn't worry about it.

Donn Cave, do**@u.washington.edu
Oct 10 '05 #2
Marc Carter <mc*****@uk.ibm.com> wrote:
import subprocess,select,sys

speakers=[]
lProc=[]

for machine in ['box1','box2','box3']:
p = subprocess.Popen( ('echo '+machine+';sleep 2;echo goodbye;sleep
2;echo cruel;sleep 2;echo world'), stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stdin=None, universal_newlines=True )
lProc.append( p )
speakers.append( p.stdout )

while speakers:
speaking = select.select( speakers, [], [], 1000 )[0]
for speaker in speaking:
speech = speaker.readlines()
if speech:
for sentence in speech:
print sentence.rstrip('\n')
sys.stdout.flush() # sanity check
else: # EOF
speakers.remove( speaker )
- SNIP ---------
The problem with the above is that the subprocess buffers all its output
when used like this and, hence, this automation is not informing me of
much :)


The problem with the above is that you are calling speaker.readlines()
which waits for all the output.

If you replace that with speaker.readline() or speaker.read(1) you'll
see that subprocess hasn't given you a buffered pipe after all!

In fact you'll get partial reads of each line - you'll have to wait
for a newline before processing the result, eg

import subprocess,select,sys

speakers=[]
lProc=[]

for machine in ['box1','box2','box3']:
p = subprocess.Popen( ('echo '+machine+';sleep 2;echo goodbye;sleep 2;echo cruel;sleep 2;echo world'), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=None, universal_newlines=True, shell=True)
lProc.append( p )
speakers.append( p.stdout )

while speakers:
speaking = select.select( speakers, [], [], 1000 )[0]
for speaker in speaking:
speech = speaker.readline()
if speech:
for sentence in speech:
print sentence.rstrip('\n')
sys.stdout.flush() # sanity check
else: # EOF
speakers.remove( speaker )

gives

b
o
x
1

b
o
x
3

b
o
x
2

pause...

g
o
o
d
b
y
e

etc...

I'm not sure why readline only returns 1 character - the pipe returned
by subprocess really does seem to be only 1 character deep which seems
a little inefficient! Changing bufsize to the Popen call doesn't seem
to affect it.
--
Nick Craig-Wood <ni**@craig-wood.com> -- http://www.craig-wood.com/nick
Oct 11 '05 #3
Donn Cave wrote:
If you want to use select(), don't use the fileobject
functions. Use os.read() to read data from the pipe's file
descriptor (p.stdout.fileno().) This is how you avoid the
buffering.

Thankyou, this works perfectly. I figured it would be something simple.

Marc
Oct 11 '05 #4
Marc Carter <mc*****@uk.ibm.com> writes:
The problem with the above is that the subprocess buffers all its output
when used like this and, hence, this automation is not informing me of
much :)


You may want to take a look at my asyncproc module. With it, you
can start subprocesses and let them run in the background without
blocking either the subprocess or your own process, while still
collecting their output.

You can download it from

http://www.lysator.liu.se/~bellman/d...d/asyncproc.py

I suspect that it doesn't work under MS Windows, but I don't use
that OS, and thus can't test it.
--
Thomas Bellman, Lysator Computer Club, Linköping University, Sweden
"Beware of bugs in the above code; I have ! bellman @ lysator.liu.se
only proved it correct, not tried it." ! Make Love -- Nicht Wahr!

Oct 11 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

17
by: Michael McGarry | last post by:
Hi, I am just starting to use Python. Does Python have all the regular expression features of Perl? Is Python missing any features available in Perl? Thanks, Michael
2
by: Do Re Mi chel La Si Do | last post by:
Hi! This script (under Win-XP + P-2.4.1) : import subprocess p1=subprocess.Popen(r'cmd /cdir *.* /S /W /B', stdout=subprocess.PIPE) chaineretour=p1.stdout.read() run OK if called from...
3
by: Darren Dale | last post by:
I'm a developer on the matplotlib project, and I am having trouble with the subprocess module on windows (Python 2.4.2 on winXP). No trouble to report with linux. I need to use _subprocess instead...
5
by: Cameron Laird | last post by:
Question: import subprocess, StringIO input = StringIO.StringIO("abcdefgh\nabc\n") # I don't know of a compact, evocative, and # cross-platform way to exhibit this behavior. # For now, depend...
9
by: Clodoaldo Pinto Neto | last post by:
Output from the shell: $ set | grep IFS IFS=$' \t\n' Output from subprocess.Popen(): "IFS=' \t\n" Both outputs for comparison:
9
by: Phoe6 | last post by:
Hi all, Consider this scenario, where in I need to use subprocess to execute a command like 'ping 127.0.0.1' which will have a continuous non- terminating output in Linux. # code # This...
6
by: Eric_Dexter | last post by:
I am having trouble contolling vim with subprocess on a windows machine. It appears that vim comes up on the machine all right and it sometimes looks like it is doing the searchs what I am asking...
7
by: Samuel A. Falvo II | last post by:
I have a shell script script.sh that launches a Java process in the background using the &-operator, like so: #!/bin/bash java ... arguments here ... & In my Python code, I want to invoke...
1
by: yogamatt1970 | last post by:
I have some code which runs on a number of different machines, however I see problems on one particular Solaris box. When I call Popen.wait(), the following exception is raised: .. . . File...
3
by: Jeremy Sanders | last post by:
Hi - I have some code which works under linux. It starts a remote python process using subprocess and communicates to it via a pipe created by os.pipe. As far as I understand, child processes...
0
by: lllomh | last post by:
Define the method first this.state = { buttonBackgroundColor: 'green', isBlinking: false, // A new status is added to identify whether the button is blinking or not } autoStart=()=>{
2
by: DJRhino | last post by:
Was curious if anyone else was having this same issue or not.... I was just Up/Down graded to windows 11 and now my access combo boxes are not acting right. With win 10 I could start typing...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 4 Oct 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
0
by: Aliciasmith | last post by:
In an age dominated by smartphones, having a mobile app for your business is no longer an option; it's a necessity. Whether you're a startup or an established enterprise, finding the right mobile app...
2
by: giovanniandrean | last post by:
The energy model is structured as follows and uses excel sheets to give input data: 1-Utility.py contains all the functions needed to calculate the variables and other minor things (mentions...
4
NeoPa
by: NeoPa | last post by:
Hello everyone. I find myself stuck trying to find the VBA way to get Access to create a PDF of the currently-selected (and open) object (Form or Report). I know it can be done by selecting :...
3
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be using a very simple database which has Form (clsForm) & Report (clsReport) classes that simply handle making the calling Form invisible until the Form, or all...
1
by: Teri B | last post by:
Hi, I have created a sub-form Roles. In my course form the user selects the roles assigned to the course. 0ne-to-many. One course many roles. Then I created a report based on the Course form and...
0
NeoPa
by: NeoPa | last post by:
Introduction For this article I'll be focusing on the Report (clsReport) class. This simply handles making the calling Form invisible until all of the Reports opened by it have been closed, when it...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.