保持与进程的管道保持打开状态

4 投票
2 回答
6673 浏览
提问于 2025-04-16 19:33

我有一个app,它从stdin读取数据,然后在换行后把结果返回到stdout

这里有个简单(其实有点傻)的例子:

$ app
Expand[(x+1)^2]<CR>
x^2 + 2*x + 1
100 - 4<CR>
96

打开和关闭这个app需要很多初始化和清理工作(它是一个计算代数系统的接口),所以我想尽量减少这个过程。

我想在Python中打开一个管道,给它的stdin写入字符串,然后从stdout读取结果。Popen.communicate()不适合这个,因为它会关闭文件句柄,这样就需要重新打开管道。

我试过类似于这个相关问题的做法: 如何在不破坏管道的情况下多次与进程通信?但我不太确定怎么等待输出。而且很难提前知道app处理当前输入需要多长时间,所以我不想做任何假设。我想我大部分的困惑来自这个问题: 在Python中对子进程管道进行非阻塞读取,里面提到混合高层和低层函数不是个好主意。

编辑: 抱歉之前没有提供任何代码,被打断了。这是我到目前为止尝试的代码,似乎可以工作,但我担心可能会出现一些未被注意的问题:

from subprocess import Popen, PIPE
pipe = Popen(["MathPipe"], stdin=PIPE, stdout=PIPE)         
expressions = ["Expand[(x+1)^2]", "Integrate[Sin[x], {x,0,2*Pi}]"] # ...                                                                                        
for expr in expressions:
    pipe.stdin.write(expr)                                                        
    while True:                                                                         
        line = pipe.stdout.readline()                                                    
        if line != '':     
            print line  
        # output of MathPipe is always terminated by ';'                                                                                                                         
        if ";" in line:                                                                  
            break                                                                       

这个方法可能有什么问题吗?

2 个回答

2

你可以把 stdin=subprocess.PIPE 作为参数传给 subprocess.Popen。这样做会让这个进程的输入变成一个像文件一样的对象,方便你使用:

import sys, subprocess

proc = subprocess.Popen(["mathematica <args>"], stdin=subprocess.PIPE, 
                        stdout=sys.stdout, shell=True)
proc.stdin.write("Expand[ (x-1)^2 ]") # Write whatever to the process
proc.stdin.flush()                    # Ensure nothing is left in the buffer
proc.terminate()                      # Kill the process

这会把子进程的输出直接送到你当前的 Python 进程的输出。如果你需要先读取输出并进行一些处理,也是可以的。可以查看一下 http://docs.python.org/library/subprocess.html#popen-objects

3

使用subprocess这个工具,你可能无法可靠地完成某些操作。你可以考虑使用pexpect这个库。不过,这个库在Windows系统上不太适用。如果你是在Windows上,可以试试winpexpect

另外,如果你想在Python中做一些数学相关的事情,可以看看SAGE。他们在与其他开源数学软件的对接方面做了很多工作,所以很有可能他们已经实现了你想要的功能。

撰写回答