守护进程,互斥锁,IPC,生产者与消费者模型
守护进程:
b 进程守护 a进程,当a进程执行完毕时,b进程会跟着立马结束
守护进程用途:
如果父进程结束了,子进程无需运行了,就可以将子进程设置为父进程的守护进程
例如我们qq视频聊天时,当我们退出qq时,视频界面会跟着退出,视频就是qq的守护进程
守护进程语法:
p.daemon = True
#1.未设置守护进程
from multiprocessing import Process
import time
def task():
print("子进程run")
time.sleep(2)
print("子进程over")
if __name__ == '__main__':
print("主进程run")
p = Process(target = task)
p.start()
print("主进程over")
#执行结果
# 主进程run
# 主进程over
# 子进程run
# 子进程over
#2.设置守护进程
from multiprocessing import Process
import time
def task():
print("子进程run")
time.sleep(2)
print("子进程over")
if __name__ == '__main__':
print("主进程run")
p = Process(target = task)
p.daemon = True
p.start()
time.sleep(0.5)#让子进程起来
print("主进程over")
#执行结果:
#主进程run
# 子进程run
# 主进程over
#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-------")
#打印完print main主进程就算结束了,作为守护进程的p1就挂了不会执行,而p2会执行完毕,主程序终止
#主程序的执行完毕和终止是两个概念,执行完毕是主进程的代码执行完,主进程终止 py文件停止运行
#执行结果
#main-------
#3456
#end456
强调:
设置守护进程需在子进程对象启动之前,即顺序如下:
p.daemon = True
p.start()
否则报错
Traceback (most recent call last):
File "D:/作业/12.28/test.py", line 13, in
p.daemon = True
File "D:\python3\lib\multiprocessing\process.py", line 201, in daemon
assert self._popen is None, 'process has already started'
AssertionError: process has already started
互斥锁:
多个进程共享一份数据时,可能会造成数据错乱
此时我们需要加锁处理
from multiprocessing import Process
import time
import random
def task1():
print("name1:wxx")
time.sleep(random.random())
print("age1:20")
time.sleep(random.random())
print("sex1:sm")
def task2():
print("name2:egon")
time.sleep(random.random())
print("age2:19")
time.sleep(random.random())
print("sex2:fm")
def task3():
print("name3:zb")
time.sleep(random.random())
print("age3:18")
time.sleep(random.random())
print("sex3:m")
if __name__ == '__main__':
p1 = Process(target=task1)
p2 = Process(target=task2)
p3 = Process(target=task3)
p1.start()
p2.start()
p3.start()
#执行结果
name1:wxx
# name2:egon
# name3:zb
# age2:19
# sex2:fm
# age3:18
# age1:20
# sex3:m
# sex1:sm
#如上模拟三个打印任务共享一台打印机,打印出的结果是乱的,不是我们想要的结果,此时cpu的利用率是高的
#解决办法:
#1.join改并发为串行,保证了数据不会乱,但执行顺序人为规定,丧失了公平性
from multiprocessing import Process
import time
import random
def task1():
print("name1:wxx")
time.sleep(random.random())
print("age1:20")
time.sleep(random.random())
print("sex1:sm")
def task2():
print("name2:egon")
time.sleep(random.random())
print("age2:19")
time.sleep(random.random())
print("sex2:fm")
def task3():
print("name3:zb")
time.sleep(random.random())
print("age3:18")
time.sleep(random.random())
print("sex3:m")
if __name__ == '__main__':
p1 = Process(target=task1)
p2 = Process(target=task2)
p3 = Process(target=task3)
p1.start()
p1.join()
p2.start()
p2.join()
p3.start()
#执行结果
#name1:wxx
# age1:20
# sex1:sm
# name2:egon
# age2:19
# sex2:fm
# name3:zb
# age3:18
# sex3:m
#2加入互斥锁:
from multiprocessing import Process,Lock
import time
import random
def task1(lock):
lock.acquire()
print("name1:wxx")
time.sleep(random.random())
print("age1:20")
time.sleep(random.random())
print("sex1:sm")
lock.release()
def task2(lock):
lock.acquire()
print("name2:egon")
time.sleep(random.random())
print("age2:19")
time.sleep(random.random())
print("sex2:fm")
lock.release()
def task3(lock):
lock.acquire()
print("name3:zb")
time.sleep(random.random())
print("age3:18")
time.sleep(random.random())
print("sex3:m")
lock.release()
if __name__ == '__main__':
lock = Lock()
p1 = Process(target=task1,args = (lock,))
p2 = Process(target=task2,args = (lock,))
p3 = Process(target=task3,args = (lock,))
p1.start()
p2.start()
p3.start()
#保证了数据不乱,而且随机执行,公平
互斥锁:当多个进程共享一份数据,对数据进行修改时,可能会导致数据错乱,加入互斥锁后,进程间抢锁,抢到锁的进程执行自己的代码,期间由于锁被抢走了,没有锁给剩下的进程抢,剩下的进程处于阻塞状态,当抢到锁的进程执行完自己的所有代码,释放出锁,剩下的进程又开始抢,直到最后一个进程抢到锁执行完毕自己的代码
用途:当多个进程共享一份数据并要操作数据时,保证了数据的安全性,不会错乱
强调:1.window系统,子进程的内存空间和父进程的内存空间完全独立,互不影响,此时多个子进程应该抢同一个锁,所以我们在if name == “main”中,新建一个锁,然后把锁传给各个子进程,保证了子进程抢的是同一把锁
2.抢到锁后,执行完代码,一定要记得释放锁
3.使用lock时,只可require一次,不可连续require
RLock可重入锁
首先是互斥锁
锁几次要开几次
死锁:
死锁的前提是有多把锁
程序遇到锁请求就会卡主,等释放
正常开发时,一把锁足够使用,不要开多把锁
IPC inter process communication 进程间通信
1.共享数据
2.在内存里
3.帮我们自动加锁
1.通过文件
可以传输大文件,IO时间长,从硬盘读数据慢
2.管道:基于内存,速度快,单向通讯,使用麻烦
3.队列,申请共享内存空间
传输数据不能太大,速度快,
不只用于进程间通讯,也是一种常见的数据容器
特点是:先进先出
对比堆栈刚好相反:后进先出
队列语法
Queue
q = Queue(1)
q.put()放入任何类型都可以
当放满时会阻塞,
q.put(data,block = True, timeout = None)
三个参数,数据,是否阻塞,超时时间
当放满时,设置不阻塞时,会报错
q.get()
q.get(block = True,timeout = None)
是否阻塞,超时时间
当取完时,设置不阻塞时,会报错
生产者消费者模型:
1.生产者不停生产
2.消费者不停消费
3.生产者消费者之间以队列进行数据沟通
生产者消费者模型
在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。
为什么要使用生产者和消费者模式
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。
什么是生产者消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。