Сохранение трубы для процесса открытым - PullRequest
4 голосов
/ 14 июня 2011

У меня есть 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 , где указано, что смешивание функций высокого и низкого уровня не является хорошей идеей.

EDIT : Извините, что я не дал никакого кода раньше, меня прервали. Это то, что я пробовал до сих пор, и, похоже, это работает, я просто волнуюсь, что что-то идет не так незамеченным:

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 ]

3 голосов
/ 14 июня 2011

Используя подпроцесс, вы не можете сделать это надежно. Возможно, вы захотите посмотреть, используя библиотеку pexpect . Это не будет работать в Windows - если вы в Windows, попробуйте winpexpect .

Кроме того, если вы пытаетесь делать математические вещи в Python, посмотрите SAGE . Они много работают над взаимодействием с другим математическим программным обеспечением с открытым исходным кодом, поэтому есть шанс, что они уже сделали то, что вы пытаетесь.

2 голосов
/ 14 июня 2011

Возможно, вы могли бы передать stdin=subprocess.PIPE в качестве аргумента subprocess.Popen. Это сделает процесс 'stdin доступным как обычный файловый объект:

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.

...