文章目录

  • 一、基本概念
  • 二、僵尸进程
  • 三、孤儿进程
  • 3.1 multiprocessing
  • 3.2 fork
  • 四、知识扩展


一、基本概念

在前面的博文里,我们介绍到:正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程到底什么时候结束。 当一个进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。也就是说:父进程会默认等待子进程的执行,在所有子进程都结束之后,父进程再结束。

二、僵尸进程

僵尸进程:主进程在创建子进程的时候,如果子进程退出,而父进程并没有调用waitwaitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

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()

python主进程与子进程切换 python 子进程_孤儿进程

三、孤儿进程

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被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()

python主进程与子进程切换 python 子进程_多进程_02

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()

python主进程与子进程切换 python 子进程_孤儿进程_03

四、知识扩展

在Linux中,有这么一个机制:父进程无论什么时候都可以获取到子进程的的 一些数据。那么当子进程任务执行完毕后,确实结束了,但是仍然保留一些数据,目的是为了让父进程能够获取这些信息。Linux中可以调用waitwaitpid来彻底清除子进程的残留信息。

在Python中已经封装了处理僵尸进程的操作,所以我们无需关心。孤儿进程的话,因为它是没有父进程的进程,那么孤儿进程这个重任就落到了init进程身上,它会处理做好一切善后工作,因此孤儿进程并不会有什么危害。