python 和子进程 实时交互

xiaoxiaota 2011-03-02 10:49:46
我有一个父进程和子进程需要实时交互的应用,下面是一个例子:

子进程subpro.py
import os
import sys

opt1 = raw_input('this is opt1 raw input:')
print 'opt1 is:',opt1
opt2 = raw_input('this is opt2 raw input:')
print 'opt2 is:',opt2
opt3 = raw_input('this is opt3 raw input:')
print 'opt3 is:',opt3
opt4 = raw_input('this is opt4 raw input:')
print 'opt4 is:',opt4

父进程:
p = subprocess.Popen("python subpro.py", stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)   #1111

while True:
line = p.stdout.readline()
print line
if not line:
break

if line.startswith('this is opt1'):
opt = 'aaa'
elif line.startswith('this is opt2'):
opt = 'bbb'
elif line.startswith('this is opt3'):
opt = 'ccc'
elif line.startswith('this is opt4'):
opt = 'ddd'

p.stdin.write(opt+os.linesep)

也就是说父进程需要提供给子进程一些输入,而输入的内容根据子进程中读到的内容而不同
我上面这段程序好像会死锁,停在了line = p.stdout.readline()
非得在 #1111 下加上类似p.stdin.write('aaa'+os.linesep) 这样的才可以继续进行。。。

俺分数不多,还是新手,请高手指点~~~

...全文
789 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
angel_su 2011-03-03
  • 打赏
  • 举报
回复
Traceback (most recent call last):
File "mytry.py", line 98, in <module>
callmib(modulename)
File "mytry.py", line 86, in callmib
p.stdin.write(opt+os.linesep)
IOError: [Errno 32] Broken pipe

估计就是子进程程已退出,父进程继续写的问题,自行操作p.stdin/stdout/stder的话p.wait()这个就不用了吧,没见子进程输出空行,那么应该在循环里p.stdin.write()前poll一下不然就只有等错退出。。。
xiaoxiaota 2011-03-03
  • 打赏
  • 举报
回复
哈哈哈,终于解决, 谢谢楼上两位,特别是iambic!
你提的建议我一一学习了,并会在以后应用。因为想在工作中写些有用的脚本,我才刚开始学这门语言,很喜欢它的简洁,这个问题还是折腾了不少时间 :(

根本原因就是你说的第二点,因为缺少了“else"子句,当主程序从子程序的”print 'opt1 is:',opt1“语句中得到输出”opt1"时,因为它既不是以“this is opt1”开头,又不是以“this is opt2”开头,所以问题就来了。

比较汗的是,我最后是通过pdb一句一句的调试才发现问题的。
pdb很好用,很多命令都和GDB一样。

继续努力学习中。。。。

结贴
iambic 2011-03-02
  • 打赏
  • 举报
回复
在回复中把你最新的代码重新贴出来。
“不行”到底是你一楼贴的python脚本还是“另外的可执行程序”?
xiaoxiaota 2011-03-02
  • 打赏
  • 举报
回复
我试了下,不行呢~
并且在我的应用中子进程其实是另外的可执行程序,父只能从子进程的输出中获取信息再传递相应信息到子进程。
xiaoxiaota 2011-03-02
  • 打赏
  • 举报
回复
谢谢,现在貌似不能修改原贴了,我先试试
iambic 2011-03-02
  • 打赏
  • 举报
回复
readline要读到换行。raw_input()本身不输出换行,你自然等不到换行。
加个换行试试:
raw_input('this is opt1 raw input:\n')

iambic 2011-03-02
  • 打赏
  • 举报
回复
把代码格式化过放到代码标签里。
your code here...
iambic 2011-03-02
  • 打赏
  • 举报
回复
你的代码里很有多问题,虽然有些算不上错误,但都是不好的习惯,会耽误你的时间。
1. 许多东西混在一起,有些输出又是多行的,根本分不清楚哪些是谁打印的了(或者根本没有意识到你自己弄混了)。多带些东西,这样你不会把父进程的输出当成子进程的,或者把换行漏掉。比如:
print '>>{x}[%s]' % line

2. 父进程里的if..elif缺少else,如果你得到的输出是意想不到的输出,就会走一些奇怪的逻辑,等你意识到不对的时候就已经晚到猜不出来是哪里出错了。有elif的时候尽量写else,或者在里面打log,或者直接throw一个error。
3. 你的log太长了。诸如“this is opt1'”,容易打错,就算没打错出问题的时候也要话时间去检查这里究竟打错了没有。阅读的时候也麻烦。
4. 子进程里的print是干什么的?是单纯的做logging,还是想和父进程交互?如果本意是做logging,你可能要把这行去掉,因为print会被父进程吃掉,而不是直接打印到控制台(因为你用了管道)。
5. 还是我之前说的,你自己测试就应该用你贴出来的代码。虽然你说“不要看行号”,但别人还是要从代码里找这行究竟在哪里,是不是有好几个write(),如果有好几个write究竟是哪一个,即使只有一个他也要做这个确认工作。如果你直接就能给出正确的行号,就省了这个麻烦,节省了别人的时间。这是小问题,但是一个人做事(特别是这种在网络上请人帮忙的事)就应该像写代码一样,干干净净,没一点多余,没一点疏漏,恰到好处。这样大家看了才都高兴。

xiaoxiaota 2011-03-02
  • 打赏
  • 举报
回复
不好意思,“先视行号”是笔误,应该是“无视行号“。
我测试的代码和贴出的代码唯一的区别就是,测试代码中多一些注释,其它都一模一样的,所以我说不要看出错信息中的行号。

子进程不是无限循环,但里面有”opt1=sys.stdin.readline()“在没有得到输入之前,应该不会退出的呀?
我已经将子进程的三个标准流都指向了subprocess.PIPE。所以我不理解为什么上面的程序会出现”broken pipe"错误(这个pipe是什么时候关掉的?)

我期望的输出是:
this is opt1 raw input:

opt1 is: aaa

this is opt2 raw input:

opt2 is: bbb ===>希望这里是bbb,而不是实际输出的aaa

谢谢不吝赐教!
iambic 2011-03-02
  • 打赏
  • 举报
回复
没看明白什么你说的“先视行号”是什么意思。
不说别的,你的子进程又不是无限循环,肯定很快就结束啊。你的父进程里循环几次出错(因为子进程结束了)不是很正常吗?
另外你测试代码的时候不要测试你原来的代码,测试你贴出来给大家看的简化过的代码。否则你说一套做一套出问题了还要想是哪一套的问题不是浪费时间吗。至少从我的角度,我不愿意把问题浪费在一段可能没有问题的代码上。
xiaoxiaota 2011-03-02
  • 打赏
  • 举报
回复
谢谢iambic, 呵呵 有点进展了,但还有点问题, 我把代码都贴出来:
subpro.py

#!/usr/bin/python
import sys

sys.stdout.write('this is opt1 raw input:\n')
sys.stdout.flush()
opt1=sys.stdin.readline()
print 'opt1 is:',opt1

sys.stdout.write('this is opt2 raw input:\n')
sys.stdout.flush()
opt2=sys.stdin.readline()
print 'opt2 is:',opt2

主程序:

#!/usr/bin/python

import os
import sys
import subprocess

# call mib2c
def callmib():
exestr = 'python -u subpro.py'
p = subprocess.Popen(exestr, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)

while True:
line = p.stdout.readline()
print line
if not line:
break
if line.startswith('this is opt1'):
opt = 'aaa'
elif line.startswith('this is opt2'):
opt = 'bbb'

p.stdin.write(opt+os.linesep)

p.wait()
errout = p.stderr.read()
p.stdout.close()
p.stderr.close()
p.stdin.close()
print


# main funciton
# Step 1. make C files first time
callmib()

下面是执行结果:
$ python mytry.py
this is opt1 raw input:

opt1 is: aaa



this is opt2 raw input:

opt2 is: aaa

Traceback (most recent call last):
File "mytry.py", line 98, in <module> ===>先视行号,主程序一些无关的我没贴出来
callmib(modulename)
File "mytry.py", line 86, in callmib
p.stdin.write(opt+os.linesep)
IOError: [Errno 32] Broken pipe
iambic 2011-03-02
  • 打赏
  • 举报
回复
可能是raw_input没有自动flush。我以为raw_input会flush。有两种方式:
1. 把
raw_input('...')

改成
sys.stdout.write('...')
sys.stdout.flush()
sys.stdin.readline()

(因为你没贴代码,所以我也没测试过。反正大致如此。)
2. 启动Python子进程的时候加上-u参数。
xiaoxiaota 2011-03-02
  • 打赏
  • 举报
回复
raw_input('this is opt1 raw input:\n')

这样的话仍然不能正常执行

能否让父进程读的阻塞的地方就返回呢?如读到“this is opt1 raw input:" 因为子进程这时要等待输入,反以就从这里返回给父进程,父进程得到这段输入,再传相应的值给子进程作为输入,这样就可以实时交互了

37,719

社区成员

发帖
与我相关
我的任务
社区描述
JavaScript,VBScript,AngleScript,ActionScript,Shell,Perl,Ruby,Lua,Tcl,Scala,MaxScript 等脚本语言交流。
社区管理员
  • 脚本语言(Perl/Python)社区
  • IT.BOB
加入社区
  • 近7日
  • 近30日
  • 至今

试试用AI创作助手写篇文章吧