什么是守护进程
进程是一个正在运行的程序
守护进程也是一个普通进程
意思是一个进程可以守护另一个进程
例如
康熙要是一个进程的话,后宫佳丽都是守护者
如果康熙挂了, 后宫佳丽们要陪葬
结论:
如果b是a的守护进程,a是被守护的进程,a要是挂了,b也就随之结束了
测试:
from multiprocessing import Processimport time# 妃子的一生def task(): print("入宫了.....") time.sleep(50) print("妃子病逝了......")if __name__ == '__main__': # 康熙登基了 print("登基了.....") # 找了一个妃子 p = Process(target=task) # 设置为守护进程 必须在开启前就设置好 p.daemon = True p.start() # 康熙驾崩了 time.sleep(3) print("故事结束了!")使用场景:
父进程交给了子进程一个任务,任务还没有完成父进程就结束了,子进程就没有继续执行的意义了
例如:qq 接收到一个视频文件,于是开启了一个子进程来下载,如果中途退出了qq,下载任务就没必须要继续运行了
互斥锁 互相排斥的锁,我在这站着你就别过来,(如果这个资源已经被锁了,其他进程就无法使用了)
需要强调的是: 锁 并不是真的把资源锁起来了,只是在代码层面限制你的代码不能执行
并发将带来资源的竞争问题当多个进程同时要操作同一个资源时,将会导致数据错乱的问题如下列所示:
加join, 弊端 1.把原本并发的任务变成了穿行,避免了数据错乱问题,但是效率降低了,这样就没必要开子进程了 2.原本多个进程之间是公平竞争,join执行的顺序就定死了,这是不合理的
就是给公共资源加锁,互斥锁 互斥锁 互相排斥的锁,我在这站着你就别过来,(如果这个资源已经被锁了,其他进程就无法使用了)
锁 并不是真的把资源锁起来了,只是在代码层面限制你的代码不能执行
1.
join是固定了执行顺序,会造成父进程等待子进程 锁依然是公平竞争谁先抢到谁先执行,父进程可以做其他事情
2.最主要的区别: join是把进程的任务全部串行 锁可以锁任意代码 一行也可以 可以自己调整粒度
注意1: 不要对同一把执行多出acquire 会锁死导致程序无法执行 一次acquire必须对应一次release
l = Lock() l.acquire() print("抢到了!") l.release() l.acquire() print("强哥毛线!")注意2:想要保住数据安全,必须保住所有进程使用同一把锁
进程间通讯
通讯指的就是交换数据
进程之间内存是相互隔离的,当一个进程想要把数据给另外一个进程,就需要考虑IPC
方式:
管道: 只能单向通讯,数据都是二进制
文件: 在硬盘上创建共享文件
缺点:速度慢
优点:数据量几乎没有限制
socket:
编程复杂度较高
共享内存:必须由操作系统来分配 要掌握的方式*
优点: 速度快
缺点: 数据量不能太大
Manager提供很多数据结构 list dict等等
Manager所创建出来的数据结构,具备进程间共享的特点
from multiprocessing import Process,Manager,Lockimport timedef task(data,l): l.acquire() num = data["num"] # time.sleep(0.1) data["num"] = num - 1 l.release()if __name__ == '__main__': # 让Manager开启一个共享的字典 m = Manager() data = m.dict({"num":10}) l = Lock() for i in range(10): p = Process(target=task,args=(data,l)) p.start() time.sleep(2) print(data)需要强调的是 Manager创建的一些数据结构是不带锁的 可能会出现问题
队列是一种特殊的数据结构,先存储的先取出 就像排队 先进先出
相反的是堆栈,先存储的后取出, 就像衣柜 桶装薯片 先进后出
扩展:
函数嵌套调用时 执行顺序是先进后出 也称之为函数栈
调用 函数时 函数入栈 函数结束就出栈
from multiprocessing import Queue# 创建队列 不指定maxsize 则没有数量限制q = Queue(3)# 存储元素# q.put("abc")# q.put("hhh")# q.put("kkk")# print(q.get())# q.put("ooo") # 如果容量已经满了,在调用put时将进入阻塞状态 直到有人从队列中拿走数据有空位置 才会继续执行#取出元素# print(q.get())# 如果队列已经空了,在调用get时将进入阻塞状态 直到有人从存储了新的数据到队列中 才会继续# print(q.get())# print(q.get())#block 表示是否阻塞 默认是阻塞的 # 当设置为False 并且队列为空时 抛出异常q.get(block=True,timeout=2)# block 表示是否阻塞 默认是阻塞的 # 当设置为False 并且队列满了时 抛出异常# q.put("123",block=False,)# timeout 表示阻塞的超时时间 ,超过时间还是没有值或还是没位置则抛出异常 仅在block为True有效模型 就是解决某个问题套路
产生数据的一方称之为生产者
处理数据的一方称之为消费者
例如: 爬虫 生活中到处都是这种模型
饭店 厨师就是生产者 你吃饭的人就是消费者
生产者和消费,处理速度不平衡,一方快一方慢,导致一方需要等待另一方
原本,双方是耦合 在一起,消费必须等待生产者生成完毕在开始处理, 反过来
如果消费消费速度太慢,生产者必须等待其处理完毕才能开始生成下一个数据
将双方分开来.一专门负责生成,一方专门负责处理
这样一来数据就不能直接交互了 双方需要一个共同的容器
生产者完成后放入容器,消费者从容器中取出数据
这样就解决了双发能力不平衡的问题,做的快的一方可以继续做,不需要等待另一方
案例:
def eat(q): for i in range(10): # 要消费 rose = q.get() time.sleep(random.randint(0, 2)) print(rose,"吃完了!")# 生产任务def make_rose(q): for i in range(10): # 再生产 time.sleep(random.randint(0, 2)) print("第%s盘青椒肉丝制作完成!" % i) rose = "第%s盘青椒肉丝" % i # 将生成完成的数据放入队列中 q.put(rose)if __name__ == '__main__': # 创建一个共享队列 q = Queue() make_p = Process(target=make_rose,args=(q,)) eat_p = Process(target=eat,args=(q,)) make_p.start() eat_p.start()
转载于:https://www.cnblogs.com/haojunliancheng/p/10971432.html