Каков наилучший способ запустить несколько подпроцессов с помощью fork ()? - PullRequest
8 голосов
/ 06 октября 2008

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

Какой лучший способ решить это? Благодарю.

Ответы [ 5 ]

11 голосов
/ 06 октября 2008

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

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 ...

5 голосов
/ 07 октября 2008

Ephemient : каждый ребенок в вашем коде будет оставаться в цикле 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)
2 голосов
/ 06 октября 2008

Вы смотрели на модуль pyprocessing ?

1 голос
/ 06 октября 2008

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

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

0 голосов
/ 19 сентября 2018

Я делал это в perl раз или два. Изучал питон и хотел повторить функцию. Планировщик для неизвестного числа разветвленных задач должен отслеживать запущенные задачи, завершенные задачи и коды возврата. Этот код включает код для обработчика 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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...