python fork_python之多进程fork

本文详细介绍了Python中实现多进程的os.fork()函数,以及如何处理僵尸进程。通过示例代码展示了多进程的创建和父子进程间的交互,强调了进程间的独立性。同时,提出了两种处理僵尸进程的方法:一是通过信号处理函数SIGCHLD来收集子进程信息;二是通过轮询waitpid来定期检查并释放子进程。
摘要由CSDN通过智能技术生成

一:多进程概念

python中实现多进程是通过os.fork()这个函数来实现,这个函数和操纵系统本身结合的非常紧密,windows下就无法使用os.fork()这个函数。python中的os.fork()被调用后就会立即生成一个子进程,是通过copy父进程的地址空间和资源来实现子进程的创建,同时这个函数在子进程中返回的是0,在父进程中返回的是子进程的PID。子进程在结束父进程还未结束的时候,子进程这段时间是处于Zombie状态,可以通过ps命令查看到进程的状态,Zombie的目的是为了在子进程结束的时候可以保存一些结束信息供父进程来收集。

二:多进程的简单实现#!/usr/bin/env python

import os

def task(id):

print "work %d" %id

pid = os.fork()

if pid == 0:

print "I am a child"

task(1)

else:

print "I am father child"

执行结果如下:

I am father child

I am a child

work 1

多次执行上面的例子可能结果的顺序会不一样,子进程和父进程执行的顺序是无法预估的。

os.fork()执行后父进程继续往下执行,子进程也会从os.fork()语句之后开始运行,并且子进程拥有父进程所有的变量,但是两者是独立的。#!/usr/bin/env python

import os

import time

def task(id):

print "work %d" %id

var = 10

pid = os.fork()

if pid == 0:

print "I am a child"

var = 9

task(1)

else:

print "I am father child"

time.sleep(3)

print var

结果是:

I am father child

I am a child

work 1

10

上面这段代码演示了子进程和父进程的var这个变量是独立,在子进程中改变了var变量的值,并不影响父进程中的var变量值,两者是独立的,为了防止父进程先执行,子进程后执行,所以让父进程sleep(3)了一会再输出var的值。子进程结束后,但是父进程还没有结束的时候,子进程是出于Zombie状态的,这个需要父进程去收集子进程的信息释放子进程。如果父进程结束了子进程没有结束,那么子进程就会寄托给pid为1的进程来管理。#!/usr/bin/env python

import os

import time

pid = os.fork()

if pid == 0:

print "I am a child %d" %os.getpid()

else:

time.sleep(100)

print "done"

输出信息:

I am a child 57786

一直处于等待状态......

done

在处于等待状态的时候立刻使用ps命令查看子进程的状态

[root@localhost ~]# ps ax|grep 57786

57786 pts/4    Z+     0:00 [python] 

57792 pts/5    S+     0:00 grep 57786

通过上面的状态发现子进程处于defunct这个状态就是Zombie状态。

三:多进程处理Zombie方式一

对于处理Zimbie状态的子进程有两种方式,第一种是基于信号的处理,子进程在结束后就会发出SIGCHLD这个信号,通过singal接收到这个信号就可以进行收集了。#!/usr/bin/env python

import os,time,signal

def chldhandler(signum,stackframe):

while 1:

try:

result = os.waitpid(-1,os.WNOHANG)

except:

break

print "Reaped child process %d" % result[0]

signal.signal(signal.SIGCHLD,chldhandler)

signal.signal(signal.SIGCHLD,chldhandler)

print "Before the fork my PID is",os.getpid()

pid = os.fork()

if pid:

print "hello from the parent the child will be PID %d" %pid

print "Sleeping 10 sconds....."

time.sleep(1000)

print "sleep done"

else:

print "Child sleeping 5 seconds"

time.sleep(5)

执行结果:

Before the fork my PID is 58322

hello from the parent the child will be PID 58323

Sleeping 10 sconds.....

Child sleeping 5 seconds

Reaped child process 58323

sleep done

5秒过后子进程结束出发信号处理函数,对子进程进行了收集和处理。并且信号打断了父进程的sleep

singal是一个信号量函数,chldhandlr是一个自定义的的信号处理的handler,通过singal可以注册接收到什么信号就自动触发哪个handler

waitpid的第一个参数代表等待所有的子进程终止,第二个参数代表如果没有已经终止的子进程就立即返回。waitpid的返回结果是一个进程的PID和退出信息组成的一个元组。在while循环结束后又重新注册了信号处理函数这是因为有些unix在信号处理程序结束后就失效了,无法再次处理其他子进程,

四:多进程处理Zombie方式二

第二中处理Zombie进程的方式是轮训,父进程一段时间就去收集一下子进程,释放Zombie进行。#!/usr/bin/env python

import os,time

def reap():

while 1:

try:

result = os.waitpid(-1,os.WNOHANG)

except:

break

print "Reaped child process %d" % result[0]

print "Before the fork,my PID is",os.getpid()

pid = os.fork()

if pid:

print "Hello from the parent .The child will be PID %d" % pid

print "Parent sleeping 60 seconds"

time.sleep(60)

print "Parent sleep done"

reap()

print "Parent sleeping 60 seconds"

time.sleep(60)

print "Parent sleep done"

else:

print "Child sleeping 5 seconds..."

time.sleep(5)

print "Child terminating"

执行结果:

Parent sleeping 60 seconds

Child sleeping 5 seconds...

#等待5秒.......

Child terminating

#子进程结束了

#等待55秒父进程睡眠结束

Parent sleep done

#启动reap()去采集子进程的信息,释放子进程

Reaped child process 58595

Before the fork,my PID is 58594

Parent sleeping 60 seconds

Parent sleep done

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值