Contents
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 :
- i,o,e = select.select([pout], [], [], timeout)
- if i :
- print i[0].read()
- if i :
> 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
- 由fcntl函数将文件设为非阻塞模式,用select来判断是否有数据可读,然后用os.read读取当前可读的所有数据。