文章目录
- 一、基本概念
- 二、僵尸进程
- 三、孤儿进程
- 3.1 multiprocessing
- 3.2 fork
- 四、知识扩展
一、基本概念
在前面的博文里,我们介绍到:正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程到底什么时候结束。 当一个进程完成它的工作终止之后,它的父进程需要调用wait()
或者waitpid()
系统调用取得子进程的终止状态。也就是说:父进程会默认等待子进程的执行,在所有子进程都结束之后,父进程再结束。
二、僵尸进程
僵尸进程:主进程在创建子进程的时候,如果子进程退出,而父进程并没有调用wait
或waitpid
获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
import time, sys
from multiprocessing import Process, current_process
def func():
print('子进程PID', current_process().pid)
print('子进程退出')
def main():
print('父进程PID', current_process().pid)
p = Process(target=func)
p.start()
time.sleep(10)
print('父进程退出')
sys.exit() # 退出程序
# p.join(timeout=1) # 如果回收失败,则不回收
# timeout 父进程只会阻塞等待1秒常识回收子进程。
if __name__ == '__main__':
main()
三、孤儿进程
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init
进程(进程号为1)所收养,并由init
进程对它们完成状态收集工作。
3.1 multiprocessing
from multiprocessing import Process, current_process
import time, sys
def func():
# 孤儿进程,父进程早于子进程退出
print('子进程PID', current_process().pid)
time.sleep(10)
print('子进程退出')
def main():
print('子进程PID', current_process().pid)
p = Process(target=func)
p.start()
print('父进程退出')
sys.exit() # 退出程序
# p.join(timeout=1) # 如果回收失败,则不回收
# timeout 父进程只会阻塞等待1秒常识回收子进程。
if __name__ == '__main__':
main()
3.2 fork
import os, time
# 父进程早于子进程退出,此时子进程一直会被1号进程回收,监控
def func():
pid = os.fork() # fork()会执行分割成两部分,调用一次,返回两次,且在fork()在Linux运行。
if pid == 0: # 子进程pid为0
time.sleep(10)
print('我是子进程')
if pid > 0: # 父进程pid为子进程的PID
print('我是父进程,我开启的子进程PID是', pid)
if __name__ == '__main__':
func()
四、知识扩展
在Linux中,有这么一个机制:父进程无论什么时候都可以获取到子进程的的 一些数据。那么当子进程任务执行完毕后,确实结束了,但是仍然保留一些数据,目的是为了让父进程能够获取这些信息。Linux中可以调用wait
或waitpid
来彻底清除子进程的残留信息。
在Python中已经封装了处理僵尸进程的操作,所以我们无需关心。孤儿进程的话,因为它是没有父进程的进程,那么孤儿进程这个重任就落到了init
进程身上,它会处理做好一切善后工作,因此孤儿进程并不会有什么危害。