僵尸进程
子进程在结束之后,释放掉其占用的绝大部分内存空间以及cpu等资源,但是会留下一个称为僵尸进程的数据结构(包含子进程的pid),等待父进程处理。这种情况下的僵尸进程是无害的(待所有的子进程结束后,父进程会统一向操作系统发送回收子进程pid的请求,或者使用join(),其内部也拥有wait()方法),但是,如果父进程是一个死循环,不断的创造子进程,而又不发送回收请求,这就造成了大量的pid被占用
孤儿进程
在子进程结束之前,父进程就挂掉了,该子进程称之为孤儿进程(无害),最后会由所有进程的父进程进行发送回收请求(linux中为init进程)
守护进程
两个关键词:守护/进程
进程:其本质也是一种“子进程”
守护:伴随的意思
即,守护进程会伴随着父进程代码的执行结束而死亡(彻彻底底,而非成为僵尸进程)
为什么要用守护进程
当该进程的代码在父进程的代码执行完毕后就没有存在的意义了,则应该将该进程设置为守护进程(例如在生产者与消费者模型中,生产者是专门负责产生数据的任务,而消费者是负责处理数据的任务,当生产者对象join之后,意味生产者不再生产数据,也意味着执行父进程的下一行代码,而消费者处理的数据来自生产者,所以应该将充当消费者的子进程设置为守护进程)
如何将进程设置为守护进程
import time from multiprocessing import Process def bar(name): print("%s is running" % name) time.sleep(3) print("%s is done" % name) def foo(name): print("%s is running" % name) time.sleep(3) print("%s is done" % name) if __name__ == '__main__': p1 = Process(target=bar, args=('守护进程',)) p2 = Process(target=foo, args=('子进程',)) p1.daemon = True # 开启守护进程一定要在父进程发送请求之前 p1.start() p2.start() print('主is done')
在这种情况下,执行结果可能有三种(取决于计算机的性能)
分析之前,首先要明确的是
1.start()操作只是代表父进程向操作系统发送创建子进程的请求(而非立即产生子进程),至于什么创建,先创建谁由操作系统决定
2.产生进程是需要开辟内存空间的,为子进程分配pid,通过导入的方式将父进程的代码复制到子进程中(还有其它资源),这些都是需要一定的时间
3.守护进程是伴随着父进程的代码执行完毕而结束(而非父进程的死亡)
4.print()操作,是先在内存中产生字符串这个对象,然后将其输出到屏幕上,这也是需要一定的时间
结果一
主进程is done 子进程 is running 子进程 is done
这是由于执行两个start()之后,立即执行了print()操作,待父进程代码执行完毕后,守护进程仍然没有被创造出来
结果二
主进程is done 守护进程 is running 子进程 is running 子进程 is done
这是由于,在父进程执行print()操作的时候,守护进程被创建出来
结果三
守护进程 is running 主进程is done 子进程 is running 子进程 is done
这是由于在父进程向操作系统发送申请子进程的时候,守护进程被创建出来