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

Asked
Viewd10844

8

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

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

5 ответов

11

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

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

2

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

5

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)
 
1

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

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