什么是守护进程
在 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: 互斥锁 重点
其原理就是将要操作公共资源的代码锁起来 以保证同一时间只能有一个进程在执行这部分代码
互斥锁是什么
互相排斥的锁
优点: 可以仅将部分代码串行
注意: 必须保证锁只有一把
和 join 区别
join 是将所有子进程转为串行 锁 将部分需要的转为串行
join 固定死了任务的执行顺序 锁 多进程之间还是公平竞争
使用方式:
- 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))# 默认是阻塞的 当容器中没有位置了就阻塞 直到有人存入元素为止
扩展: 栈
也是一种特殊的容器 特殊在于 存取顺序为 先进后出
函数调用栈
调用函数时 称之为 函数入栈
函数执行结束 称之为函数出栈
生产者消费者模型:
模型就是套路 就是解决某种固定问题的固定套路
1. 守护进程 python 中的守护进程 使用场景不多 了解
2. 互斥锁
互斥锁的应用案例
3.IPC
4. 队列
5. 生产者消费者模型
多进程小结
来源: http://www.bubuko.com/infodetail-3112584.html