通过fork()运行多个子进程的最佳方法是什么?

时间:2008-10-06 15:47:59

标签: python linux

python脚本需要通过fork()生成多个子进程。所有这些子进程应该同时运行,父进程应该等待所有这些进程完成。有能力为“慢”的孩子设置一些超时会很好。 在收集所有孩子后,父进程继续处理剩余的脚本。

最好的解决方法是什么?谢谢。

5 个答案:

答案 0 :(得分: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的......

答案 1 :(得分:5)

Ephemient :代码中的每个孩子都会在工作结束后留在for循环中。他会一次又一次地岔开。而且,当孩子[]不是空的时候开始的孩子会试着在循环结束时等待他们的一些兄弟。最终有人会崩溃。这是一种解决方法:

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 :(得分:2)

你看过pyprocessing模块吗?

答案 3 :(得分:1)

与子进程通信的传统UNIX-y方式是打开管道到其标准输入/输出,并使用select()系统调用来复用父进程中的通信(可通过Python获得) ...... select模块。

如果你需要杀死一个运行缓慢的子进程,你可以保存它的进程ID(由os.fork()调用返回),然后在不再需要时使用os.kill()来终止它。当然,能够明确地与子进程通信并且告诉它自行关闭它可能会更清晰。

答案 4 :(得分:0)

我一两次都做了一次。学习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()