2005-06-29 如何非阻塞地读取子进程的输出

如何非阻塞地读取子进程的输出 引发

发件人: Hong Yuan <[email protected]>
回复: [email protected]
收件人: [email protected]
日期: 2005-6-29 下午1:51

问题

{{{我在程序中需要启动一个外部命令并读取该命令的输出。问题是这个外部命令在产 生第一部分输出后要停顿很长时间,而我并不想等到外部命令全部结束再去读取它 的输出,而想先得到第一部分的输出。

例如,假设外部程序是以下python代码:

test.py: import sys, time print 'hello'*500 sys.stdout.flush() time.sleep(100) print 'world'*500

我希望在自己的程序中设置一个timeout,读取外部进程在这个timeout时间前的所 有输出,即前500个'hello'。我的程序是这样写的:

import os, select cmd = 'python test.py' pin, pout = os.popen2(cmd) select.select([pout], [], [], timeout)[0] pout.read()

根据文档select应该等到pout有可读取的内容(即前500个'hello')时就返回,但实 际情况是它要一直到test.py全部执行完毕才返回可读的内容。

谁知道这段代码应该如何正确书写?代码运行在Linux下。 }}}

讨论

{{{发件人: Neo Chan (netkiller) <[email protected]> 回复: [email protected] 收件人: [email protected] 日期: 2005-6-29 下午2:08 }}}

   1 import select
   2 import socket
   3 import time
   4 
   5 PORT = 8037
   6 
   7 TIME1970 = 2208988800L
   8 
   9 service = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  10 service.bind(("", PORT))
  11 service.listen(1)
  12 
  13 print "listening on port", PORT
  14 
  15 while 1:
  16    is_readable = [service]
  17    is_writable = []
  18    is_error = []
  19    r, w, e = select.select(is_readable, is_writable, is_error, 1.0)
  20    if r:
  21        channel, info = service.accept()
  22        print "connection from", info
  23        t = int(time.time()) + TIME1970
  24        t = chr(t>>24&255) + chr(t>>16&255) + chr(t>>8&255) + chr(t&255)
  25        channel.send(t) # send timestamp
  26        channel.close() # disconnect
  27    else:
  28        print "still waiting"

Neo Chan (netkiller) Best Regards, 73! de BG7NYT Amateur Radio Callsign: BG7NYT


发件人: shhgs <[email protected]>
回复: shhgs <[email protected]>, [email protected]
收件人: [email protected]
日期: 2005-6-29 下午7:19

{{{> 我希望在自己的程序中设置一个timeout,读取外部进程在这个timeout时间前的所 > 有输出,即前500个'hello'。我的程序是这样写的: > > import os, select > cmd = 'python test.py' > pin, pout = os.popen2(cmd) > select.select([pout], [], [], timeout)[0]

select的作用是查看三个流的集合,发现其中的可读,可写,以及有错误报出的流。

你这里的问题,一是没有返回这个集合,所以它被当作垃圾回收了。第二select是非阻塞的,所以返回之后,它就等着执行下一句,也就是pout.read()了。这当然要等程序执行完毕才能运行。所以我觉得应该这么写:

while 1 :

> pout.read() > > 根据文档select应该等到pout有可读取的内容(即前500个'hello')时就返回,但实 > 际情况是它要一直到test.py全部执行完毕才返回可读的内容。 > > 谁知道这段代码应该如何正确书写?代码运行在Linux下。

顺便说一句,Linux下可以,Windows下不行。Windows的select只支持socket。 }}}

成果

   1 import os, fcntl, select
   2 
   3 cmd = 'python test.py'
   4 
   5 timeout = 2
   6 pin, pout = os.popen2(cmd)
   7 
   8 pout = pout.fileno()
   9 flags = fcntl.fcntl(pout, fcntl.F_GETFL)
  10 fcntl.fcntl(pout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
  11 
  12 while 1:
  13    i,o,e = select.select([pout], [], [], timeout)
  14    if i :
  15        buf = os.read(pout, 1024)
  16        if buf:
  17            print buf
  18        else:
  19            break

MicroProj/2005-06-29 (last edited 2009-12-25 07:15:12 by localhost)