Python: завершение бесконечно итеративного подпроцесса

У меня есть сценарий python, который открывает программу .exe с помощью модуля подпроцесса. Эта программа .exe представляет собой бесконечно повторяющийся сценарий, так как он будет продолжать печатать результаты каждой итерации до тех пор, пока пользователь не закроет окно. Время от времени он печатает результаты итерации в файл, заменяя предыдущие данные в файле.

Мои цели здесь заключаются в следующем:

  1. Запустите программу .exe и проверьте наличие файла, который она выводит.
  2. После того, как было показано, что файл существует, мне нужно запустить тест с файлом, чтобы увидеть, сошлась ли итерация в пределах заданного допуска. Как только итерация сойдется, мне нужно убить подпроцесс .exe.

Это мой текущий код. Он предназначен для уничтожения подпроцесса после создания файла итерации:

import subprocess
from subprocess import Popen, PIPE

fileexists = False

iteratecomms = Popen('iterate.exe', stdout=PIPE, stdin=PIPE, stderr=PIPE)

# Begin the iteration. Need to select options 1 and then 1 again at program menu
out, err = iteratecomms.communicate("1\n1\n".encode())

while (fileexists == False):
    fileexists = os.path.exists(filelocation)
else:
    Popen.kill(iteratecomms)

Я знаю, что это неверно; проблема в том, что как только я начинаю строку out, err = iteratecomms.communicate("1\n1\n".encode()), программа начинает итерацию и не переходит к следующему набору кода Python. По сути, мне нужно запустить программу .exe и в то же время проверить, создан ли файл. Однако я не могу этого сделать, потому что программа работает бесконечно.

Как я мог это обойти? Я предположил, что переход к шагу 2 (тестирование файла и завершение подпроцесса при определенных условиях) не потребует слишком много дополнительной работы; Если это не так, как я могу достичь всех своих целей?

Огромное спасибо за помощь!

Изменить: уточнено, что внешний файл перезаписывается.


person Bixx    schedule 15.07.2013    source источник
comment
Не зацикливайтесь на communicate("1\n1\n".encode()), вместо этого позвоните Popen.stdin.write("1\n1\n".encode()).   -  person martineau    schedule 16.07.2013
comment
Это работает (когда я заменяю Popen на iteratecomms); благодарю вас! Не могли бы вы представить себе, как непрерывно печатать вывод программы .exe, используя что-то вроде iteratecomms.stdout.read()?   -  person Bixx    schedule 16.07.2013
comment
В первую очередь я бы создал отдельный поток, который непрерывно считывал строки через iteratecomms.stdout.read() и помещал их в _ 2_, из которой основной поток проверял и извлекал их. Этот отдельный поток можно легко убить, когда он больше не нужен.   -  person martineau    schedule 16.07.2013
comment
Также ответы на вопрос Неблокирующее чтение в подпроцессе .PIPE на Python может быть вам полезен. (или, по крайней мере, дать вам представление о том, что искать).   -  person martineau    schedule 16.07.2013


Ответы (2)


Я бы использовал модуль многопроцессорности.

pool = multiprocessing.Pool()
def start_iteration():
    return Popen('iterate.exe', stdout=PIPE, stdin=PIPE, stderr=PIPE)
pool.apply_async(start_iteration)
while (fileexists == False):
    fileexists = os.path.exists(filelocation)
Popen.kill(???)

Единственная проблема теперь заключается в том, что вам нужно как-то найти PID процесса, не дожидаясь возврата Popen (потому что Popen никогда не должен возвращаться).

person Chris Barker    schedule 15.07.2013
comment
Popen() возвращает экземпляр класса subprocess.Popen. . - person martineau; 16.07.2013

Предполагая, что вы постоянно пытаетесь прочитать этот файл, я бы предложил запустить tail для этого файла. Это можно сделать с отдельного терминала в любой ОС семейства * nix, но в противном случае я бы ознакомился с этой статьей, чтобы узнать о реализации Python:

http://code.activestate.com/recipes/157035-tail-f-in-python/

После этого, если вы хотите убить запущенную программу, вы можете просто вызвать terminate для запущенного процесса:

import subprocess
sub = subprocess.popen(#Whatever)

#Do something

sub.terminate()
person Slater Victoroff    schedule 15.07.2013
comment
Извинения; Я новичок в Python и модуле подпроцесса. Я не совсем понимаю, как это практически применимо к моей проблеме! Этот tail использует file.tell(), который, кажется, находит текущую позицию указателя в файле; файл, который я использую, заменяется после каждой итерации; т.е. после создания файла данные текущей итерации заменяют последний набор. Проблема, с которой я столкнулся, заключается в том, чтобы установить, когда файл создается. Очень жаль, если я упустил вашу точку зрения! - person Bixx; 16.07.2013
comment
@FreeBixi, подожди, возможно, я неправильно понял. Ваша итерация постоянно удаляет и воссоздает один файл? - person Slater Victoroff; 16.07.2013
comment
@FreeBixi Omigoodness. Если у вас есть контроль над этим кодом, я бы настоятельно предложил добавить вместо переписывания по миллиарду различных причин. Помимо этого, я бы посоветовал прокрутить страницу вниз и найти последнюю n версию хвостовой функции, которая позволит вам просто взглянуть на последнюю строку или несколько строк и выяснить, соответствует ли она вашим критериям. Если вам нужно все увидеть, просто измените последнее n на какое-нибудь действительно большое число. - person Slater Victoroff; 16.07.2013
comment
К сожалению, у меня нет контроля над этим кодом, иначе я бы не стал через это проходить. Мне также нужно учитывать, что я должен сравнивать значения из всего выходного файла, а не только из последней строки. Большое спасибо за ваши предложения; потратив на эту проблему целый день, завтра попробую со свежей парой глаз! - person Bixx; 16.07.2013
comment
@FreeBixi Если вы все равно собираетесь читать все, вам следует просто писать в стандартный вывод вместо файла. - person Slater Victoroff; 16.07.2013
comment
У меня тоже были проблемы с этим; поскольку программа является итеративной и работает непрерывно, я не могу распечатать стандартный вывод, используя что-то вроде print(iteratecomms.stdout.read()). - person Bixx; 16.07.2013
comment
О, это не то, как вы должны писать в stdout. По сути, вы можете просто указать - в качестве местоположения, и оно перейдет в стандартный вывод. Запустите его в другом процессе, затем просто назначьте его файловому объекту (StringIO) и используйте его. - person Slater Victoroff; 16.07.2013