守护进程及进程数据安全问题分析
一、守护进程
1、概念
在python中 守护进程也是一个进程,
默认情况下 主进程即使代码执行完毕了 也会等待子进程结束才会结束自己
当一个进程b设置为另一进程a的守护进程时 a是被守护 b是守护进程
特点是: 当被守护a 结束时,即使b的任务没有完成也会随之结束
2、比喻:
康熙 是一个进程 妃子是康熙的守护进程
康熙驾崩了 如果妃子还活着 那就陪葬去 当然如果妃子的任务提前结束了那就立即挂了
3、案例:
from multiprocessing import Process
import time
def task():
print("zi run")
time.sleep(3)
print("zi over")
if __name__ == '__main__':
p = Process(target=task)
p.daemon = True # 将这个进程设置为了守护进程 必须在开启进程前设置
p.start()
print("主over")
二、进程安全问题
1、产生原因
当并发的多个任务,要同时操作同一个资源,就会造成数据错乱的问题
2、解决的方法
将并发操作公共资源的代码 由并发变为串行 解决安全问题,但是牺牲效率
方法1:串行方式(join):
直接使用join函数
缺点: 将任务中所有代码全都串行,此时还是不如不要开进程 ,多个进程之间原本公平竞争 join是强行规定了执行顺序
方法2:串行方式(互斥锁)
其原理就是将要操作公共资源的代码锁起来,以保证同一时间只能有一个进程在执行这部分代码
互斥锁是什么
互相排斥的锁
优点: 可以仅将部分代码串行
注意: 必须保证锁只有一把
使用方式:
from multiprocessing import Process,Lock
import time,random
def task1(mutex):
# 假设这不是访问公共资源 那么还可也并发执行
for i in range(10000):
print(1)
mutex.acquire() # 这是加锁
time.sleep(random.random())
print("-------name is nick")
time.sleep(random.random())
print("-------gender is girl")
time.sleep(random.random())
print("-------age is 18")
mutex.release() # 解锁
def task2(mutex):
for i in range(10000):
print(2)
mutex.acquire()
time.sleep(random.random())
print("++++++++name is bgon")
time.sleep(random.random())
print("++++++++gender is oldman")
time.sleep(random.random())
print("++++++++age is 48")
mutex.release()
if __name__ == '__main__':
mutex = Lock() # 创建一把互斥锁
print("创建锁了!!!!")
p1 = Process(target=task1,args=(mutex,))
p2 = Process(target=task2,args=(mutex,))
p1.start()
p2.start()
加锁 解决了安全问题 带来了效率降低的问题
锁其实只是给执行代码加了限制 本质是一个标志 为True 或False
如何使得即保证安全 又提高效率
锁的 粒度
粒度指的是被锁住的代码的多少
粒度越大锁住的越多 效率越低
3、互斥锁的案例:
抢票
def show():
with open("db.json") as f:
data = json.load(f)
print("剩余票数",data["count"])
def buy():
with open("db.json") as f:
data = json.load(f)
if data["count"] > 0:
data["count"] -= 1
with open("db.json","wt") as f2:
json.dump(data,f2)
print("抢票成功!")
def task(mutex):
show()
mutex.acquire()
buy()
mutex.release()
if __name__ == '__main__':
mutex = Lock()
for i in range(5):
p = Process(target=task,args=(mutex,))
p.start()