守护进程
- 什么是守护进程
在python中,守护进程也是一个进程,默认情况下,主进程及时代码执行完毕了也会等待子进程结束才会结束自己,当一个进程B设置为另一个进程A的守护进程时, A是被守护,B是守护进程
特点是:当被守护A结束时,即使B的任务没有完成也会随之结束
比喻:
康熙是一个进程,妃子是康熙的守护进程
康熙驾崩了,如果妃子还活着,那就陪葬去,当然如果妃子的任务提前结束了那就立即挂了
**案例
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
直接使用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
如何使得即保证安全 又提高效率
锁的 粒度
粒度指的是被锁住的代码的多少
粒度越大锁住的越多 效率越低
互斥锁的案例
# 抢票
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()
IPC
Inter-Process Communication
空间复用 中内存隔离开了多个进程直接不能直接交互
IPC指的就是进程间通讯
几种方式 :
1.创建一个共享文件
缺点: 效率较低
优点: 理论上交换的数据量可以非常大
适用于: 交互不频繁 且数据量较大的情况
2.共享内存 (主要方式)
缺点: 数据量不能太大
优点: 效率高
适用于: 交互频繁,但是数据量小
3.管道
管道也是基于文件的 它是单向的 编程比较复杂
4.socket
编程复杂,更适用于基于网络来交换数据
共享内存的第一种方式
Manger
可以为我们创建 进程间同步的容器,但是没有处理安全问题 ,所以并不常用
Queue
Queue 翻译为队列 是一种特殊的容器 特殊之处在于存取顺序为先进先出
可以帮我们完成进程间通讯
from multiprocessing import Queue
q = Queue(2) # 创建队列 并且同时只能存储2个元素
q.put(1)
q.put(2)
# q.put(3,block=True,timeout=3) # 默认是阻塞的 当容器中没有位置了就阻塞 直到有人从里面取走元素为止
print(q.get())
print(q.get())
print(q.get(block=True,timeout=3))# 默认是阻塞的 当容器中没有位置了就阻塞 直到有人存入元素为止
扩展: 栈
也是一种特殊的容器 特殊在于 存取顺序为 先进后出
函数调用栈
调用函数时 称之为 函数入栈
函数执行结束 称之为函数出栈