Проблема: У меня плохо разработанная программа Fortran (я не могу ее изменить, я застрял с ней), которая берет текстовый ввод из stdin и других входных файлов и записывает результаты вывода текста в stdout и другие выходные файлы. Размер ввода и вывода довольно большой, и я хотел бы избежать записи на жесткий диск (медленная работа). Я написал функцию, которая выполняет итерацию по строкам нескольких входных файлов, и у меня также есть парсеры для множественного вывода. Я действительно не знаю, прочитала ли программа сначала все входные данные, а затем начинает выводить или запускает вывод при чтении ввода.
Цель: Чтобы иметь функцию, которая передает внешнюю программу с тем, что она хочет, и анализирует вывод, как он поступает из программы, без записи данных в текстовые файлы на жестком диске.
Исследование: Наивный способ использования файлов:
from subprocess import PIPE, Popen
def execute_simple(cmd, stdin_iter, stdout_parser, input_files, output_files):
for filename, file_iter in input_files.iteritems():
with open(filename ,'w') as f:
for line in file_iter:
f.write(line + '\n')
p_sub = Popen(
shlex.split(cmd),
stdin = PIPE,
stdout = open('stdout.txt', 'w'),
stderr = open('stderr.txt', 'w'),
bufsize=1
)
for line in stdin_iter:
p_sub.stdin.write(line + '\n')
p_sub.stdin.close()
p_sub.wait()
data = {}
for filename, parse_func in output_files.iteritems():
# The stdout.txt and stderr.txt is included here
with open(filename,'r') as f:
data[filename] = parse_func(
iter(f.readline, b'')
)
return data
Я попытался и subprocess модуль для совместной работы внешней программы. Дополнительные файлы ввода/вывода обрабатываются с именованными каналами и multiprocessing. Я хочу передать stdin с помощью итератора (который возвращает строки для ввода), сохраните stderr в списке и проанализируйте stdout, как он поступает из внешней программы. Вход и выход могут быть довольно большими, поэтому использование communicate
невозможно.
У меня есть синтаксический анализатор в формате:
def parser(iterator):
for line in iterator:
# Do something
if condition:
break
some_other_function(iterator)
return data
Я посмотрел на это решение, используя select
, чтобы выбрать соответствующий поток, однако я не знаю, как заставить его работать с моим парсером stdout и как кормить stdin.
Я также смотрю asyncio модуль, но, как я вижу, у меня будет такая же проблема с синтаксическим анализом толстого.