Функции os.spawnv и os.spawnve впервые были представлены как инструменты запуска программ в Windows, напоминающие по своему действию комбинацию функций fork/exec в Unix-подобных системах. На сегодняшний день эти функции доступны на обеих платформах, в Windows и в Unix-подобных системах, а кроме того, были добавлены варианты, повторяющие функциональность других членов семейства os.exec.
В последние версии Python был включен переносимый модуль subprocess с целью заменить эти функции. Фактически руководство по библиотеке Python включает примечание, отмечающее, что в составе этого модуля имеются более мощные и эквивалентные инструменты, которым следует отдавать предпочтение перед функциями os.spawn. Кроме того, новейший пакет multiprocessing, в совокупности с функциями os.exec, позволяет добиться тех же результатов переносимым способом, как мы уже видели выше. Тем не менее функции семейства os.spawn по- прежнему доступны и могут встретиться вам в действующих сценариях на языке Python.
Функции из семейства os.spawn запускают программу, указанную в командной строке, в виде нового процесса в Windows и в Unix-подобных системах. По своему действию они напоминают комбинацию функций fork/exec в Unix и могут использоваться как альтернатива функциям system и popen, с которыми мы уже познакомились. В следующем примере выполняется запуск программы на языке Python двумя традиционными способами (во втором случае дополнительно выполняется чтение стандартного потока вывода программы):
C:\…\PP4E\System\Processes> python
>>> print(open(‘makewords.py’).read())
print(‘spam’) print(‘eggs’) print(‘ham’)
>>> import os
>>> os.system(‘python makewords.py’)
spam eggs ham 0
>>> result = os.popen(‘python makewords.py’).read()
>>> print(result)
spam eggs ham
Функции, эквивалентные функции os.spawn, имеющие чуть более сложную сигнатуру, что обеспечивает более полный контроль над способом запуска программы, — позволяют получить тот же эффект:
> >> os.spawnv(os.P_WAIT, r’C:\Python31\python’, (‘python’, ‘makewords.py’)) spam eggs ham
0
> >> os.spawnl(os.P_NOWAIT, r’C:\Python31\python’, ‘python’, ‘makewords.py’) 1820
> >> spam
eggs ham
Из всех этих способов функция spawn больше всего напоминает прием ветвления программ в Unix. В действительности она не копирует вызывающий процесс (поэтому операции, использующие общие дескрипторы, не работают), но может использоваться для запуска программы Windows, выполняемой совершенно независимо от вызвавшей программы. Сценарий в примере 5.35 делает сходство с шаблонами программирования в Unix еще более очевидным. Он запускает программу с помощью комбинации fork/exec в Unix-подобных системах (включая оболочку Cygwin) или вызывает os.spawnv в Windows.
Пример 5.35. PP4E\System\Processes\spawnv.py
запускает параллельно 10 копий child.py; для запуска программ в Windows использует spawnv (как fork+exec); флаг P_OVERLAY обозначает замену, флаг P_DETACH перенаправляет stdout потомка в никуда; можно также использовать переносимые инструменты из модуля subprocess или из пакета multiprocessing!
import os, sys
for i in range(10):
if sys.platform[:3] == ‘win’:
pypath = sys.executable
os.spawnv(os.P_NOWAIT, pypath, (‘python’, ‘child.py’, str(i))) else:
pid = os.fork()
if pid != 0:
print(‘Process %d spawned’ % pid) else:
os.execlp(‘python’, ‘python’, ‘child.py’, str(i))
print(‘Main process exiting.’)
Чтобы понять, как действуют эти примеры, вам необходимо познакомиться с аргументами, которые передаются функциям spawn. В этом сценарии мы передаем функции os.spawnv флаг режима запуска процесса, полный путь к выполняемому файлу интерпретатора Python и кортеж строк, представляющих команду оболочки, запускающую новую программу. Путь к выполняемому файлу интерпретатора Python доступен сценариям как sys.executable. В общем случае флаг режима запуска процесса может состоять из следующих предопределенных значений:
os.P_NOWAIT и os.P_NOWAITO
Функции spawn возвращают управление сразу после запуска нового процесса и возвращают его числовой идентификатор ID. Доступны в Unix и Windows.
os.P_WAIT
Функции spawn не возвращают управление, пока новый процесс не завершится, и в случае успеха возвращают код его завершения, в противном случае — отрицательный номер сигнала («-signal»), если работа процесса была прервана сигналом. Доступен в Unix и Windows.
os.P_DETACH и os.P_OVERLAY
Флаг P_DETACH похож на флаг P_NOWAIT, но при этом новый процесс отсоединяется от консоли вызывающего процесса. Если был использован флаг P_OVERLAY, текущая программа будет замещена (как при использовании функции os.exec). Доступен в Windows.
Фактически в семействе spawn насчитывается восемь различных функций. Все они выполняют запуск программ, но несколько отличаются сигнатурами. Символ «l» в их именах означает, что аргументы программы передаются в виде списка, символ «p» означает, что поиск выполняемого файла программы будет производиться с учетом системного пути, а символ «e» означает, что функции может быть передан словарь, определяющий окружение порождаемой программы: функция os.spawnve, например, действует так же, как функция os.spawnv, но принимает в дополнительном четвертом аргументе словарь, определяющий иное окружение для порождаемой программы (по умолчанию порождаемые процессы наследуют окружение родительского процесса):
os.spawnl(mode, path, …)
os.spawnle(mode, path, …, env)
os.spawnlp(mode, file, …) # только в Unix
os.spawnlpe(mode, file, …, env) # только в Unix os.spawnv(mode, path, args) os.spawnve(mode, path, args, env)
os.spawnvp(mode, file, args) # только в Unix
os.spawnvpe(mode, file, args, env) # только в Unix
Имена этих функций повторяют имена и сигнатуры функций из семейства os.exec, поэтому дополнительные подробности, касающиеся отличий между их вариантами, вы найдете в описании функций os.exec, выше в этой главе. В отличие от функций os.exec только половина функций os.spawn, не использующих системный путь (то есть без символа «p» в их именах), в настоящее время реализованы в версии Python для Windows. В Windows поддерживаются все флаги режимов запуска процессов, но флаги os.P_DETACH и os.P_OVERLAY недоступны в Unix. Со временем перечисленные особенности могут измениться, поэтому обязательно проверьте их описание в руководстве по библиотеке Python или запустите встроенную функцию dir, передав ей имя модуля os после его импортирования.
Ниже приводится вывод сценария из примера 5.35, запущенного в Windows. Он порождает 10 копий программы child.py, с которой мы встречались выше в этой главе:
C:\…\PP4E\System\Processes> type child.py import os, sys print(‘Hello from child’, os.getpid(), sys.argv[1])
C:\…\PP4E\System\Processes> python spawnv.py
Hello from child -583587 0
Hello from child -558199 2
Hello from child -586755 1
Hello from child -562171 3
Main process exiting.
Hello from child -581867 6
Hello from child -588651 5
Hello from child -568247 4
Hello from child -563527 7
Hello from child -543163 9
Hello from child -587083 8
Обратите внимание, что эти копии программы выводят свою информацию в случайном порядке, а родительская программа завершается раньше, чем завершатся все дочерние; все эти программы действительно выполняются в Windows параллельно. Обратите также внимание, что вывод дочерней программы появляется в окне консоли, где был запущен сценарий spawnv.py, — при использовании флага P_NOWAIT стандартный вывод попадает на родительскую консоль, но отправляется в никуда, если использовать флаг P_DETACH (что не является ошибкой при порождении программ с графическим интерфейсом).
После того как я продемонстрировал эту функцию, следует отметить, что оба модуля, subprocess и multiprocessing, на сегодняшний день предлагают более переносимые альтернативные способы запуска программ с использованием командной строки. Фактически если функции os.spawn не обеспечивают вам какого-то уникального поведения, без которого вы не можете обойтись (например, управление всплывающим окном консоли в Windows), платформозависимые отрезки кода, присутствующие в примере 5.35, можно было бы полностью заменить переносимыми инструментами из пакета multiprocessing, использованными в примере 5.33.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011