Как мы узнали выше, независимые программы обычно взаимодействуют между собой с помощью общесистемных инструментов, таких как сокеты и файлы fifo, изученные нами ранее. Процессы, порождаемые с помощью пакета multiprocessing, также могут пользоваться этими инструментами, однако благодаря их близкому родству мы можем использовать дополнительные механизмы IPC, предоставляемые этим пакетом.
Как и потоки выполнения, пакет multiprocessing предназначен для параллельного выполнения функций, а не для запуска отдельных программ. Порожденные функции могут использовать такие инструменты, как os.system, os.popen и модуль subprocess для запуска других программ, если выполняемая операция может заблокировать вызывающий процесс, но часто нет никакого смысла порождать процесс таким способом, чтобы запустить другую программу (другую программу можно запустить, пропустив этот шаг). Фактически в Windows пакет multiprocessing в настоящее время использует ту же функцию запуска процессов, что и модуль subprocess, поэтому нет смысла использовать первый из них для запуска двух процессов.
Существует также возможность запускать новые программы из дочерних процессов с помощью инструментов, таких как функции os.exec*, с которыми мы встречались выше. Порождая процесс переносимым способом с помощью пакета multiprocessing и запуская в нем новую программу, мы тем самым запускаем независимую программу и эффективно решаем проблему отсутствия функции os.fork в стандартной версии Python для Windows.
Как правило, запуск новой программы не предполагает передачу каких-либо ресурсов конструктору Process (при запуске новая программа затрет программу, выполнявшуюся до нее в этом процессе), но этот конструктор представляет собой переносимый эквивалент комбинации функций fork/exec в Unix. Кроме того, программы, запущенные таким способом, точно так же могут использовать более традиционные инструменты IPC, такие как сокеты и именованные каналы, с которыми мы встречались выше в этой главе. Этот прием иллюстрируется в примере 5.33.
Пример 5.33. PP4E\System\Processes\multi5.py
Использует пакет multiprocessing для запуска независимых программ, с помощью os.fork или других функций
import os
from multiprocessing import Process
def runprogram(arg):
os.execlp(‘python’, ‘python’, ‘child.py’, str(arg))
if __name__ == ‘__main__’: for i in range(5):
Process(target=runprogram, args=(i,)).start() print(‘parent exit’)
Этот сценарий запускает 5 экземпляров сценария child.py из примера 5.4 в виде независимых процессов и не ждет их завершения. Ниже приводится вывод этого сценария, запущенного в Windows, после удаления лишних строк с системным приглашением к вводу, которые произвольно появляются в середине вывода (в Cygwin сценарий действует точно так же, но в этом случае вывод не перемешивается):
C:\…\PP4E\System\Processes> type child.py import os, sys print(‘Hello from child’, os.getpid(), sys.argv[1])
C:\… |
\PP4E\System\Processes> multi5.py |
parent Hello |
exit from child 9844 2 |
Hello |
from child 8696 4 |
Hello |
from child 1840 0 |
Hello |
from child 6724 1 |
Hello |
from child 9368 3 |
Этот прием невозможно применить к потокам выполнения, потому что все потоки выполняются в пределах одного процесса, — запуск новой программы уничтожит все эти потоки выполнения. Хотя данный прием едва ли будет выполняться с той же скоростью, как комбинация a fork/exec в Unix, он, по крайней мере, предоставляет похожий и переносимый способ для Windows.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011