Python 2.2.1 and select()

Francesco Bochicchio bockman at virgilio.it
Tue Mar 25 05:38:47 EDT 2008


Il Mon, 24 Mar 2008 17:58:42 -0400, Derek Martin ha scritto:

> Hi kids!
> 
> I've got some code that uses select.select() to capture all the output
> of a subprocess (both stdout and stderr, see below).  This code works as
> expected on a variety of Fedora systems running Python > 2.4.0, but on a
> Debian Sarge system running Python 2.2.1 it's a no-go.  I'm thinking
> this is a bug in that particular version of Python, but I'd like to have
> confirmation if anyone can provide it.
> 
> The behavior I see is this:  the call to select() returns: [<file
> corresponding to sub-proc's STDOUT>] [] []
> 
> If and only if the total amount of output is greater than the specified
> buffer size, then reading on this file hangs indefinitely. For what it's
> worth, the program whose output I need to capture with this generates
> about 17k of output to STDERR, and about 1k of output to STDOUT, at
> essentially random intervals.  But I also ran it with a test shell
> script that generates roughly the same amount of output to each file
> object, alternating between STDOUT and STDERR, with the same results.
> 
> Yes, I'm aware that this version of Python is quite old, but I don't
> have a great deal of control over that (though if this is indeed a
> python bug, as opposed to a problem with my implementation, it might
> provide some leverage to get it upgraded)...  Thanks in advance for any
> help you can provide.  The code in question (quite short) follows:
> 
> def capture(cmd):
>     buffsize = 8192
>     inlist = []
>     inbuf = ""
>     errbuf = ""
> 
>     io = popen2.Popen3(cmd, True, buffsize) inlist.append(io.fromchild)
>     inlist.append(io.childerr)
>     while True:
>         ins, outs, excepts = select.select(inlist, [], []) for i in ins:
>             x = i.read()
>             if not x:
>                 inlist.remove(i)
>             else:
>                 if i == io.fromchild:
>                     inbuf += x
>                 if i == io.childerr:
>                     errbuf += x
>         if not inlist:
>             break
>     if io.wait():
>         raise FailedExitStatus, errbuf
>     return (inbuf, errbuf)
> 
> If anyone would like, I could also provide a shell script and a main
> program one could use to test this function...

>From yor description, it would seem that two events occurs:

- there are actual data to read, but in amount less than bufsize.
- the subsequent read waits (for wathever reason) until a full buffer can 
be read, and therefore lock your program.

Try specifying bufsize=1 or doing read(1). If my guess is correct, you 
should not see the problem. I'm not sure that either is a good solution
for you, since both have performance issues.

Anyway, I doubt that the python library does more than wrapping the 
system call, so if there is a bug it is probably in the software layers
under python.

Ciao
----
FB



More information about the Python-list mailing list