Ⅰ 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