Как лучше всего запускать несколько подпроцессов через fork ()?

Сценарий python должен запускать несколько подпроцессов через fork (). Все эти дочерние процессы должны выполняться одновременно, а родительский процесс должен ждать их завершения. Было бы неплохо иметь возможность установить тайм-аут для «медленного» ребенка. Родительский процесс продолжает обработку остальной части скрипта после того, как все дочерние элементы собраны.

Как лучше всего это решить? Спасибо.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
8
0
11 313
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Вы смотрели модуль пипроцессинг?

Традиционный UNIX-y способ взаимодействия с подпроцессами - открыть каналы для их стандартного ввода / вывода и использовать системный вызов select() для мультиплексирования связи в родительском процессе (доступно в Python через ... модуль select). .

Если вам нужно убить медленно работающий дочерний процесс, вы можете просто сохранить его идентификатор процесса (возвращенный вызовом os.fork()), а затем использовать os.kill(), чтобы убить его, когда он больше не нужен. Конечно, было бы проще иметь возможность явно связываться с дочерним процессом и скажи это, чтобы отключиться.

Ответ принят как подходящий

Простой пример:

import os
chidren = []
for job in jobs:
    child = os.fork()
    if child:
        children.append(child)
    else:
        pass  # really should exec the job
for child in children:
    os.waitpid(child, 0)

Задержать медлительного ребенка - немного больше; вы можете использовать wait вместо waitpid и отбирать возвращаемые значения из списка дочерних элементов вместо ожидания каждого из них по очереди (как здесь). Если вы настроили alarm с обработчиком SIGALRM, вы можете прекратить ожидание после указанной задержки. Это все стандартные файлы UNIX, а не специфичные для Python ...

должен ли дочерний процесс завершиться после выполнения?

zuo 06.11.2013 07:54

@zuo Дочерний процесс должен exec (заменяя его дочерним процессом, который нужно запустить) или _exit.

ephemient 06.11.2013 09:59

Эфемиент: каждый дочерний элемент в вашем коде останется в цикле for после завершения своей работы. Он будет разветвляться снова и снова. Более того, дочерние элементы, которые запускаются, когда children [] не пусто, будут пытаться дождаться некоторых из своих братьев в конце цикла. В конце концов кто-нибудь разобьется. Это обходной путь:

import os, time

def doTheJob(job):
    for i in xrange(10):
        print job, i
        time.sleep(0.01*ord(os.urandom(1)))
        # random.random() would be the same for each process

jobs = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
imTheFather = True
children = []

for job in jobs:
    child = os.fork()
    if child:
        children.append(child)
    else:
        imTheFather = False
        doTheJob(job)
        break

# in the meanwhile 
# ps aux|grep python|grep -v grep|wc -l == 11 == 10 children + the father

if imTheFather:
    for child in children:
        os.waitpid(child, 0)

Как говорится в комментарии в моем исходном коде, необходимо заменить «pass» на «exec (job) or similar». Если это будет сделано, все будет работать должным образом. Кроме того, вам лучше использовать os.exit () вместо установки imTheFather.

ephemient 07.04.2009 18:46

@ephemient Но почему os._exit() лучше?

Alois Mahdal 19.06.2013 22:03

@AloisMahdal используется для выхода из разветвленного дочернего процесса docs.python.org/2/library/os.html#os._exit

Marconi 05.07.2013 16:44

Я делал это на Perl раз или два. Изучал python и хотел воспроизвести функцию. Планировщик для неизвестного количества разветвленных задач должен отслеживать запущенные задачи, завершенные задачи и коды возврата. Этот код включает код для обработчика SIGCHLD, родительской задачи и простой дочерней задачи.

#!/usr/bin/env python3
import signal, traceback
import os, subprocess
import time
#
#   sigchild handler for reaping dead children
#
def handler(signum, frame):
#
#   report stat of child tasks  
    print(children)
#
#   use waitpid to collect the dead task pid and status
    pid, stat = os.waitpid(-1, 0)
    term=(pid,stat)
    print('Reaped: pid=%d stat=%d\n' % term)
#
#   add pid and return code to dead kids list for post processing
    ripkids.append(term)
    print(ripkids)
    print('\n')
#
#   update children to remove pid just reaped
    index = children.index(pid)
    children.pop(index)
    print(children)   
    print('\n')

# Set the signal handler 
signal.signal(signal.SIGCHLD, handler)

def child():
   print('\nA new child ',  os.getpid())
   print('\n')
   time.sleep(15)
   os._exit(0)  

def parent():
#
# lists for started and dead children
   global children
   children = []
   global ripkids
   ripkids = []

   while True:
      newpid = os.fork()
      if newpid == 0:
         child()
      else:
         pidx = (os.getpid(), newpid)
         children = children+[newpid]
         print("parent: %d, child: %d\n" % pidx)
         print(children)
         print('\n')
      reply = input("q for quit / c for new fork")
      if reply == 'c': 
          continue
      else:
          break

parent()

Другие вопросы по теме