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

10 投票
4 回答
14156 浏览
提问于 2025-04-11 09:25

有一个Python脚本需要通过fork()来创建多个子进程。这些子进程应该同时运行,而父进程则需要等待所有子进程完成。如果能给某个“慢”的子进程设置一个超时时间,那就更好了。父进程在收集完所有子进程后,才会继续执行脚本的其他部分。

那么,最好的解决办法是什么呢?谢谢。

4 个回答

1

传统的、类UNIX的方式与子进程进行沟通,就是打开管道,连接它们的标准输入和输出,然后在父进程中使用select()这个系统调用来处理这些通信(在Python中可以通过select模块来实现)。

如果你需要结束一个运行缓慢的子进程,你可以保存它的进程ID(这个ID是通过os.fork()调用返回的),然后在不需要它的时候用os.kill()来结束它。当然,能够明确地与子进程沟通,并告诉它自己关闭,可能会更干净一些。

7

Ephemient: 你代码里的每个子进程在完成工作后都会留在循环里。他们会不断地重新创建自己。而且,当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)
12

简单的例子:

import os
children = []
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特有的……

撰写回答