设为首页 收藏本站
查看: 866|回复: 0

[经验分享] python之多进程fork

[复制链接]

尚未签到

发表于 2018-8-4 09:20:34 | 显示全部楼层 |阅读模式
  一:多进程概念
  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] <defunct>
  
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、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-546266-1-1.html 上篇帖子: Python模块——doctest 下篇帖子: python:__add__方法使用
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表