Обратите внимание, что в последней проверке, в предыдущем фрагменте программного кода, не предпринимается попытка прочитать вывод команды. В подобных ситуациях может потребоваться запускать целевой сценарий в небуферизованном режиме, то есть запускать интерпретатор Python с флагом —u, или изменить сценарий, чтобы он выталкивал выходной буфер вручную с помощью функции sys.stdout.flush. В противном случае текст, выводимый в стандартный поток вывода, не будет вытолкнут из буфера стандартного потока вывода при вызове функции os._exit. По умолчанию при подключении канала, как в данном примере, стандартный поток вывода работает в режиме полной буферизации — при подключении к терминалу в буфер помещается только одна строка:
> >> pipe = os.popen(‘python testexit_os.py’)
> >> pipe.read() # буферы не выталкиваются при выходе ‘’
> >> pipe = os.popen(‘python —u testexit_os.py’) # принудительный
> >> pipe.read() # небуферизованный режим
‘Bye os world\n’
Странно, но, несмотря на то, что имеется возможность передавать функциям os.popen и subprocess.Popen аргумент, управляющий режимом и буферизацией, — в данном случае это не поможет. Аргументы передаются инструментам со стороны вызывающего процесса, с конца канала, работающего в порожденной программе, как поток ввода, а не как поток вывода:
> >> pipe = os.popen(‘python testexit_os.py’, ‘r’, 1) # построчная буферизация
> >> pipe.read() # но мой канал — это не поток вывода программы!
> >> from subprocess import Popen, PIPE
> >> pipe = Popen(‘python testexit_os.py’, bufsize=1, stdout=PIPE) # для моего
> >> pipe.stdout.read() # канала —
b’’ # не поможет
Аргументы, определяющие режим буферизации, воздействуют на поток вывода вызывающего процесса, через который он записывает данные в стандартный поток ввода команды, а не на поток вывода команды, откуда вызывающий процесс читает данные.
При необходимости запускаемый сценарий может сам, вручную выталкивать выходные буферы — периодически или перед принудительным завершением. Подробнее о буферизации мы поговорим, когда будем обсуждать возможность возникновения ситуации взаимоблокировки далее в этой главе, и еще раз — в главах 10 и 12, где мы узнаем, как все это увязывается с сокетами. Поскольку мы вспомнили про модуль subprocess, рассмотрим теперь предоставляемые им инструменты завершения программ.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011