第26天 父进程与子进程 僵尸进程与孤儿进程 守护进程 互斥锁与信号量

运行一个py程序,就是开启了一个python解释器的进程,py程序下开的子进程也是python解释器的进程。
在python解释器里面启动一个py文件,等同于只开启了一个python解释器进程,本质原理就是python解释器启动后,
读取了py文件的内容,通过解释器的运行来执行文件内容。

pid是操作系统中任务的唯一编号

在windows系统下:
    通过cmd命令查看所有pid进程命令:tasklist
    通过pid号查看进程的命令:tasklist | findstr (pid号)
    强制杀死进程的命令:taskkill /F /PID (pid号)
在linux系统下:
    查看所有进程的命令:ps aux
    通过pid号查看进程的命令:ps aux | grep (pid号)
    强制杀死进程的命令:kill -9 (pid号)

父进程与子进程

from multiprocessing import Process
import os
import time

def task():
    print("父进程:%s  子进程:%s" % (os.getppid(), os.getpid()))
    time.sleep(500)


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

    print("主进程的pid:%s 主进程的父进程pid:%s" % (os.getpid(), os.getppid()))

主进程的pid:7272(该运行文件的pid)     主进程的父进程pid:10208(pycharm的pid,windows系统下通过cmd查看不到主进程的父进程也是显示python解释器的)
父进程:7272(该运行文件的pid)       子进程:15684(该文件下子进程task的pid)

僵尸进程孤儿进程(都是运行在Linux系统下的概念)
start和jion自带僵尸进程清理功能

僵尸进程
是linux操作系统中一种特殊的数据结构
是linux系统中所有的子进程在死后都会进入僵尸。
僵死进程:子进程退出后,会将该进程的重型资源释放掉(cpu,内存,打开的文件),子进程的进程描述符仍然保存在系统中,比如pid。
程序正常结束才会产生僵尸进程,如果强制关闭父进程,操作系统会把父进程已经运行结束的子进程全部删除,也就不会产生僵尸进程了

僵尸进程的危害
系统的pid号是有限的,僵尸进程保留的信息如果一直不被释放,一直累计会导致没有可用的pid号而导致系统不能产生新的进程

linux系统中处理僵尸进程的方法
如果应用程序的僵尸进程回收比较滞后,可以通过命令通知父进程回收僵尸进程的儿子:kill -CHLD (父进程的pid)
如果应用程序没有设计僵尸进程回收的机制,那么可以直接杀死父进程,让进程号为1的init进程控制父进程下的所有子进程
init回自动回收僵尸进程【强制杀死进程的命令:kill -9 (pid号)】

孤儿进程(无害)
一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程
父进程死后,孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

守护进程(了解型知识点)
守护进程守护的是主进程的代码,而不是生命周期

主进程代码运行完毕,守护进程就会结束
from multiprocessing import Process
import os, time


def task():
    print("进程%s开启" % os.getpid())
    time.sleep(10)
    print("进程%s结束" % os.getpid())


if __name__ == '__main__':
    p = Process(target=task)
    p.daemon = True   # 这一行代码会把子进程变成守护代码,主进程运行完,子进程也就运行完了,不会打印进程结束的那行代码
    p.start()
    print("主:%s" % os.getpid())
    time.sleep(3)

案例

from multiprocessing import Process
import time


def foo():
    print(123)
    time.sleep(1)
    print("end123")


def bar():
    print(456)
    time.sleep(3)
    print("end456")


if __name__ == '__main__':
    p1 = Process(target=foo)
    p2 = Process(target=bar)

    p1.daemon = True
    p1.start()
    p2.start()
    print("main-------")
    
可能会出现的情况(大部分都是第一种情况)
"""
main-------
456
end456
"""

"""
main-------
123
456
end456
"""

"""
123
main-------
456
end456
"""

互斥锁与信号量

加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,降低了速度,却保证了数据安全。
虽然可以用文件共享数据实现进程间通信,但问题是:
1.效率低(共享数据基于文件,而文件是硬盘上的数据)
2.需要自己加锁处理

信号量指的是同一时间有多把锁并发运行

互斥锁代码实现

db1.json
{
    
    "COUNT": 3}
# 模拟抢票案例,需求:利用互斥锁实现局部串行的效果(串行并不是真正意义上的串行,还是由cpu去实现并行,只不过是一旦有进程抢到了锁,其他的进程都是在阻塞的状态)
from multiprocessing import Process
from multiprocessing import Lock  # 导入Lock,调用Lock会的得到一把锁,这把锁就是互斥锁
import json
import os
import time


def check():
    with open("db1.json", mode="rt", encoding="utf-8")as f:
        time.sleep(1)        # 模拟网络延迟
        dic = json.load(f)
        print("%s查看剩余票数为:%s" % (os.getpid(), dic["COUNT"]))


def get():
    with open("db1.json", mode="rt", encoding="utf-8")as f:
        time.sleep(1)       # 模拟网络延迟
        dic = json.load(f)

    if dic["COUNT"] > 0:
        dic["COUNT"] -= 1
        time.sleep(3)       # 模拟网络延迟
        with open("db1.json", mode="wt", encoding="utf-8")as f:
            json.dump(dic, f)
            print("%s购票成功" % os.getpid())

    else:
        print("购票失败")

def func(mutex):
    check()

    mutex.acquire()  # 抢锁
    get()
    mutex.release()  # 释放锁
    # cup也是处于并行的状态,但是一旦有进程抢到了锁,其他进程就是阻塞的状态

    # with mutex:  写法2
    #     get()


if __name__ == '__main__':
    mutex = Lock()

    for i in range(10):
        p = Process(target=func, args=(mutex,))
        p.start()

    print("主")

猜你喜欢

转载自blog.csdn.net/Yosigo_/article/details/112913541