首页 > 系统相关 >Process对象补充,僵尸孤儿进程,守护进程

Process对象补充,僵尸孤儿进程,守护进程

时间:2024-05-20 16:31:22浏览次数:18  
标签:__ task Process print 进程 import os 守护

Ⅰ Process对象的其他方法或属性(了解)

【一】查看当前进程的进程ID

【1】进程ID

  • 指的是某个应用程序运行在系统之上的标志

【2】查看所有进程

  • Windows系统

    • CMD 命令行 tasklist 即可查看
  • Mac系统 /linux

    • 终端运行 ps aux 即可查看

【3】如何根据指定进程号查看进程

  • Mac系统 /linux

    • 终端运行 ps aux|grep PORT/PID 即可查看
  • Windows系统

    • CMD 命令行 tasklist |findstr PORT/PID即可查看

【4】在代码中查看进程ID

(1)from multiprocessing import current_process

(2)获取当前进程的PID

current_process().pid == os.getpid()

(3)查看当前进程的父ID

 os.getppid()

(1)查看当前进程的进程号current_process().pid 方法

from multiprocessing import Process, current_process
import time


def task():
    # 查看当前进程的 进程(PID) 号
    print(f'当前程序:>>>>{current_process().pid} 正在运行')
    time.sleep(2)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()

    print(f'这是主程序:>>>{current_process().pid}')

    # 这是主程序:>>>9176
    # 当前程序:>>>>3820 正在运行

(2)查看当前进程的进程号os.getpid() 方法

from multiprocessing import Process
import os
import time


def task():
    # 查看当前进程的 进程(PID) 号
    print(f'当前程序:>>>>{os.getpid()} 正在运行')
    time.sleep(2)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()

    print(f'这是主程序:>>>{os.getpid()}')

    # 这是主程序:>>>9928
    # 当前程序:>>>>3912 正在运行

(3)查看当前进程的父进程的进程号os.getppid() 方法

from multiprocessing import Process
import os
import time


def task():
    # 查看当前进程的 进程(PID) 号
    print(f'当前程序:>>>>{os.getpid()} 正在运行')
    # 查看当前进程的 父进程(PID) 号
    print(f'当前程序的父进程:>>>>{os.getppid()} 正在运行')
    time.sleep(2)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()

    print(f'这是主程序:>>>{os.getpid()}')
    print(f'这是主程序的父进程:>>>{os.getppid()}')

    # 这是主程序:>>>22236
    # 这是主程序的父进程:>>>17720
    # 当前程序:>>>>3756 正在运行
    # 当前程序的父进程:>>>>22236 正在运行

【二】杀死当前进程p.terminate()

 task.terminate()
  • 告诉操作系统帮我去杀死当前进程
  • 但是需要一定的时间。
  • 代码的运行速度极快

【三】判断当前进程是否存活p.is_alive()

task.is_alive()
from multiprocessing import Process
import os
import time


def task():
    # 查看当前进程的 进程(PID) 号
    print(f'当前程序:>>>>{os.getpid()} 正在运行')
    print(f'当前程序的父进程:>>>>{os.getppid()} 正在运行')

    time.sleep(2)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()

    # 杀死当前进程 - 需要给操作系统一点缓冲时间
    p.terminate()
    time.sleep(0.2)
    # 判断当前进程是否存活
    print(p.is_alive())

    print(f'这是主程序:>>>{os.getpid()}')
    print(f'这是主程序的父进程:>>>{os.getppid()}')

    # 主进程正常
    # 调用程序中的子进程被杀死
    # False
    # 这是主程序:>>>16796
    # 这是主程序的父进程:>>>17720

Ⅱ 僵尸进程和孤儿进程

【一】引入

  • 我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。
  • 子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。
  • 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。

【二】僵尸进程

【1】什么是僵尸进程

  • 僵尸进程是指完成了自己的任务,但父进程没有正确地释放它所占用的系统资源
  • 你开了一个pycharm ---> 将 pycharm 关闭 --> 任务管理器所有的关于 pycharm 的进程应该都被关闭
  • 有时候你会发现,有某几个 pycharm 进程任然在后台运行 --> 本来这部分资源应该被回收,结果因为还在运行,占用系统资源
  • 导致它仍然存在于进程列表中
  • 但已经停止了运行。
  • 这些僵尸进程会占据一定的系统内存,并在一定程度上影响系统的性能。

【2】解决办法(UNⅨ系统)

  • 因此,UNⅨ提供了一种机制可以保证父进程可以在任意时刻获取子进程结束时的状态信息

    • 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。
      • 但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)
    • 直到父进程通过wait / waitpid来取时才释放.
      • 但这样就导致了问题,如果进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的
      • 如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。
  • 任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。

    • 这是每个子进程在结束时都要经过的阶段。
    • 如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。
    • 如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。
    • 如果父进程在子进程结束之前退出,则子进程将由init接管。
    • init将会以父进程的身份对僵尸状态的子进程进行处理。

【3】示例

  • 当子进程开设后,该进程死后不会立刻释放占用的进程号
    • 因为要让父进程能够查看到开设的子进程的一些基本信息
      • 占用的 PID 号,运行时间等
  • 所有的进程都会步入僵尸进程
    • 父进程不死并且在无限制的创建子进程并且子进程也不结束
  • 如何回收子进程占用的 PID 号
    • 父进程等待子进程运行结束
    • 父进程调用 join 方法
import multiprocessing
import time


def work(name):
    print(f'{name} is starting .... ')
    time.sleep(2)
    print(f'{name} is ending .... ')


def main():
    for i in range(3):
        task = multiprocessing.Process(
            target=work,
            args=(f'task_{i}',)
        )
        task.start()


if __name__ == '__main__':
    print(f'main process starting ...')
    main()
    print(f'main process ending ...')
# 主程序已经结束子程序还在运行  
# main process starting ...
# main process ending ...
# task_0 is starting .... 
# task_1 is starting .... 
# task_2 is starting .... 
# task_1 is ending .... 
# task_0 is ending .... 
# task_2 is ending .... 

【三】孤儿进程

【1】什么是孤儿进程

  • 孤儿进程则是指父进程在子进程终止之前就已经退出了
  • 导致子进程失去了与父进程通信的能力。
  • 这些孤儿进程将被init进程接管
  • init进程会等待它的状态信息并释放它的系统资源。

【2】示例

  • 子进程存活,父进程意外死亡
    • 没有父进程来帮助回收 PID 号
  • 解决办法
    • 操作系统会开设一个儿童福利院(init 进程)专门管理孤儿进程回收相关资源
import os
import sys
import time

if __name__ == '__main__':
    pid = os.getpid()
    ppid = os.getppid()
    print('我是父进程 :>>> ', 'pid', pid, 'ppid', ppid)
    pid = os.fork()
    # 执行pid=os.fork()则会生成一个子进程
    # 返回值pid有两种值:
    #    如果返回的pid值为0,表示在子进程当中
    #    如果返回的pid值>0,表示在父进程当中
    if pid > 0:
        print('父进程终止')
        sys.exit(0)

    # 保证主线程退出完毕
    time.sleep(1)
    print('我是子进程 :>>>> ', os.getpid(), os.getppid())

    # 子进程已经被pid为1的init进程接收了
    # 所以僵尸进程在这种情况下是不存在的,存在只有孤儿进程而已
    # 孤儿进程声明周期结束自然会被init来销毁。
    # 我是父进程 :>>>  pid 86270 ppid 61564
    # 父进程终止

【四】僵尸进程和孤儿进程谁的危害性更大?

  • 僵尸进程的危害性更大
  • 因为僵尸进程一直会持续存在在后台占用资源
  • 孤儿进程因为主进程死亡后让然有init进程接管并销毁

在Linux上能看到效果,在Windows不行

  • 例如有个进程,它定期的产 生一个子进程,这个子进程需要做的事情很少,做完它该做的事情之后就退出了,因此这个子进程的生命周期很短
  • 但是,父进程只管生成新的子进程,至于子进程 退出之后的事情,则一概不闻不问
  • 这样,系统运行上一段时间之后,系统中就会存在很多的僵死进程,倘若用ps命令查看的话,就会看到很多状态为Z的进程。
  • 严格地来说,僵死进程并不是问题的根源,罪魁祸首是产生出大量僵死进程的那个父进程。
  • 因此,当我们寻求如何消灭系统中大量的僵死进程时,答案就是把产生大 量僵死进程的那个元凶枪毙掉(也就是通过kill发送SIGTERM或者SIGKILL信号啦)。
  • 枪毙了元凶进程之后,它产生的僵死进程就变成了孤儿进 程,这些孤儿进程会被init进程接管,init进程会wait()这些孤儿进程,释放它们占用的系统进程表中的资源
  • 这样,这些已经僵死的孤儿进程 就能瞑目而去了。

以后开启多进程 ---> start 扔到列表中 --> 遍历join

Ⅲ 守护进程

【一】什么是守护进程

  • 守护进程 (daemon) 是在计算机系统启动时就已经运行,并且一直在后台运行的一类特殊进程
  • 特殊在只要系统不关机,就会一直存在
  • MySQL ---> 安装MySQL服务(TCP服务端) ---> 关机会导致服务端关闭 --> MySQL服务加一个守护进程
  • 只要系统不关机,MySQL服务就会一直在后台运行,除非你主动将他杀死
  • 它们通常不与用户直接交互,也不接受标准输入和输出,而是在后台执行某种任务或提供某种服务。
  • 守护进程往往是由系统管理员手动启动的,它们可以在系统启动时自动启动,一直运行在后台,直到系统关闭或被停止。
  • 常见的守护进程包括网络服务 (如 web 服务器、邮件服务器、 ftp 服务器等)、日志记录系统 (如系统日志服务、应用程序日志服务等) 等。
  • 守护进程通常在后台运行,不需要用户交互,并且有较高的权限,因此编写守护进程需要特别注意安全性和稳定性。

【二】案例

【1】主进程死亡,子进程未死亡

from multiprocessing import Process
import time


def task(name):
    print(f'皇太妃 :>>{name}>>正常存活')
    time.sleep(2)
    print(f'皇太妃 :>>{name}>>正常死亡')


if __name__ == '__main__':
    print(f'皇帝 :>>> silence >>> 执掌江山')
    p = Process(target=task, args=('紫月',))

    p.start()

    print(f'皇帝 :>>> silence >>> 寿终正寝')
    # 主进程结束而子进程未结束
   
# 皇帝 :>>> silence >>> 执掌江山
# 皇帝 :>>> silence >>> 寿终正寝
# 皇太妃 :>>紫月>>正常存活
# 皇太妃 :>>紫月>>正常死亡

【2】主进程死亡,子进程必死亡

(1)正确用法

  • 将设置主进程的方法在 调用主进程 的前面声明
from multiprocessing import Process
import time


def task(name):
    print(f'皇太妃 :>>{name}>>正常存活')
    time.sleep(2)
    print(f'皇太妃 :>>{name}>>正常死亡')


if __name__ == '__main__':
    print(f'皇帝 :>>> silence >>> 执掌江山')
    p = Process(target=task, args=('紫月',))

    # 将进程 p 设置成守护进程
    p.daemon = True

    p.start()

    print(f'皇帝 :>>> silence >>> 寿终正寝')
    # 主进程结束而子进程未结束

# 皇帝 :>>> silence >>> 执掌江山
# 皇帝 :>>> silence >>> 寿终正寝
# 只要主程序结束(死)的够快 子程序就运行不了(陪葬够快)

(2)错误用法

  • 进程已经开始,但是在开始后给进程加锁
from multiprocessing import Process
import time


def task(name):
    print(f'皇太妃 :>>{name}>>正常存活')
    time.sleep(2)
    print(f'皇太妃 :>>{name}>>正常死亡')


if __name__ == '__main__':
    print(f'皇帝 :>>> silence >>> 执掌江山')
    p = Process(target=task, args=('紫月',))

    p.start()

    # 将进程 p 设置成守护进程
    p.daemon = True

    print(f'皇帝 :>>> silence >>> 寿终正寝')
    # 主进程结束而子进程未结束

# assert self._popen is None, 'process has already started'
# AssertionError: process has already started
# 报错原因:进程已经开始了无法再次重置进程状态
 
# 皇太妃 :>>紫月>>正常存活
# 皇太妃 :>>紫月>>正常死亡

标签:__,task,Process,print,进程,import,os,守护
From: https://www.cnblogs.com/zyb123/p/18202278

相关文章

  • process.poll() 检查子进程运行状态
    在Python的subprocess模块中,poll()方法是Popen类的实例方法,用于检查一个子进程是否已经结束,如果已经结束,它将返回子进程的退出状态码;如果子进程尚未结束,它将返回None。以下是poll()方法的一些关键点:检查子进程状态:poll()允许你检查一个子进程是否已经完成执行,而无需等待它实际......
  • subprocess.run 和 subprocess.Popen 区别
    subprocess.run:是阻塞式,非交互性,返回值:不是我们想要的执行结果或相关信息,而是一个CompletedProcess类型对象subprocess.Popen:非阻塞式,交互性,返回值:是一个Popen对象,<subprocess.Popenobjectat0x0000000002B17668>Popen对象的stdin、stdout和stderr是三个文件句柄,可以像文......
  • 多线程和多进程 - 初窥
    一、说明在平常工作中,我们使用top命令查看一台linux服务器的cpu使用情况时,会发现某个进程的cpu使用率会超过100%,这是为什么?二、举例实验环境为CentOS7.6+Python2.71.多线程、多进程在操作系统中的表现形式我们首先看两个例子,test1.py和test2.py,都是执行死循环,test1.py两......
  • ptrace attach 修改进程内存
    #include<stdio.h>#include<stdlib.h>#include<sys/ptrace.h>#include<stdint.h>#include<errno.h>#include<sys/wait.h>intmain(intargc,char*argv[]){ void*addr1; void*addr2; pid_tattack_pid=-1; if(......
  • PHP的多样化执行方式(parallel PHP多线程实现,原生协程实现,多进程实现,ZTS、NTS、TS又是
    进程、线程、协程进程:应用程序的启动实例,运行起的代码叫进程,有独立的内存空间,类比工厂的P个(P=1单进程,P>1多进程)车间。线程:线程是CPU调度的最小单位,是进程内的执行单元,多个线程共享所属进程的资源。类比车间内的T个员工(T=1单线程,T>1多线程)车间。协程:类似线程,协程是用户态(CPU受......
  • KPCR进程概念
    1.KPCR进程概念KPCR介绍KPCR是CPU的控制结构FS段寄存器在R0(FS=0x30)的时候指向KPCR结构FS段寄存器在R3(FS=0x3b)的时候指向当前线程的TEB(线程)线程结构是运行在CPU上面,所以线程结构是放在CPU上的kd>dt_KPCRntdll!_KPCR+0x000NtTib:_NT_TIB+0x0......
  • 进程
    2.进程KPROCESS这里我们使用驱动管理程序kd>dt_kprocess86de0d20ntdll!_KPROCESS+0x000Header:_DISPATCHER_HEADER+0x010ProfileListHead:_LIST_ENTRY[0x86de0d30-0x86de0d30]//基本都是空的+0x018DirectoryTableBase:0xbeda71e0//......
  • 孤儿进程和僵尸进程
     孤儿进程和僵尸进程是操作系统中两种不同的进程状态,它们有着不同的特征和产生原因。1.孤儿进程:-孤儿进程是指父进程退出或意外终止后,子进程仍然在操作系统中运行的情况。由于子进程的父进程已经不存在,操作系统将其托付给init进程(在Unix/Linux系统中是进程号为1的init进程......
  • multiprocess.Process模块
    【3.0】多进程操作【一】multiprocessing模块介绍python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程。Python提供了multiprocessing。multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务......
  • 打开、关闭、切换App以及清除App进程,操作so easy!
    此文章来源于项目官方公众号:“AirtestProject”版权声明:允许转载,但转载必须保留原链接;请勿用作商业或者非法用途#一、前言很多新手同学在写自动化测试脚本的时候,打开、关闭、切换App的方式还是使用最基础的方式,也有同学在交流群内多次询问是否有打开、关闭、切换App以及清除A......