## 守护进程
```python
def task(name=None,age=None):
print("子进程为守护进程")
time.sleep(5)
print("守护结束",name,age)
if __name__=="__main__":
print("父进程开始")
p=Process(target=task,kwargs={"name":"owen","age":18})
#设置好守护进程,必须在start之前设置
# p.daemon=True
p.start()
time.sleep(2)
print("父进程结束")
p.terminate()
'p.terminate()强制结束一个进程,不会清理:p有子进程会变成孤儿进程,如果p有锁,会变成死锁,特别注意!!!
#守护进程:子进程守护父进程,父进程结束,子进程没运行完也要结束.
```
## 并发导致的资源竞争/数据安全问题及互斥锁
```python
当多个进程同时要操作同一个资源时,将会导致数据错乱的问题
from multiprocessing import Process,Lock
import time,random
def task(lock):
#上锁,本质就是给所有上锁的进程,加个相同协议的标签.
lock.acquire()
print("hello,i am jerry")
time.sleep(random.randint(0,1))
print("age is 18")
lock.release()
def task2(lock):
lock.acquire()
print("hello i am owen")
time.sleep(random.randint(0,1))
print("age is 19")
lock.release()
if __name__=="__main__":
lock=Lock()
p1=Process(target=task,args=(lock,))
p2=Process(target=task2,args=(lock,))
p1.start()
p2.start()
#不能对同一把锁执行多次acquire,会锁死导致后续加锁程序无法运行
#一次acquire 必须配合一次release!
#lock的本质也是将并发强制改成串行执行.同在start方法后面跟join方法一样.
"""区别在于:1.join是固定了执行顺序,会造成父进程等待子进程
锁依然是公平竞争谁先抢到谁先执行,父进程可以做其他事情
2.最主要的区别:join是把进程的任务全部串行,锁可以锁任意代码 一行也可以 可以自己调整粒度"""
3.互斥锁的粒度:粒度越大意味着锁住的代码越多 效率越低
粒度越小意味着锁住的代码越少 效率越高
```
## IPC进程间通讯
```python
from multiprocessing import Process,Manager,Lock
import time
def task(data,l,i):
l.acquire()
print(i)
name=data["name"]
time.sleep(0.1)#延时,这样导致所有进程读到的都是"owen"
data["name"]=name+"is"
print(i)
l.release()
if __name__=="__main__":
#让Manager开启一个共享的字典
m=Manager()
data=m.dict({"name":"owen"})
l=Lock()#锁对象.
for i in range(9):
p=Process(target=task,args=(data,l,i))
p.start()
time.sleep(2)
print(data)
#Manager没有封装lock方法,需要自己加.Manager开启的共享空间,是在父进程的
#内存中的.父进程结束,子进程没有结束,报错:管道被关闭.
#Manager对象下面有三种数据类型容器dict,list,Queue.
```
## Queue队列
```python
from multiprocessing import Queue
q=Queue(3)#创建队列,不指定maxsize,则没有数量限制
#存储元素
q.put("a")
q.put("b")
q.put("c")
# @1:print("执行这一步")
print(q.get())#当把这一步注销的时候:@!、@2
q.put("d")#如果容量满了,在调用put时将进入阻塞状态,
# 直到有人从队列中拿走数据才会继续执行
# @2:print("这一步不会执行")
print(q.get())
print(q.get())
print(q.get())
print(q.get())# 如果队列已经空了,在调用get时将进入阻塞状态
#直到有人从存储了新的数据到队列中 才会继续
print("不会往下执行```")
q.put("e")
#block 表示是否阻塞 默认是阻塞的
#当设置为False 并且队列为空时 抛出异常
q.get(block=True,timeout=2)
# block 表示是否阻塞 默认是阻塞的
#当设置为False 并且队列满了时 抛出异常
# q.put("123",block=False,)
# timeout 表示阻塞的超时时间 ,超过时间还是没有值或还是没位置则抛出异常 仅在block为True有效
```
## 生产者、消费者模型
```python
import time,random
from multiprocessing import Process,Queue
def consume(q):#消费者
for i in range(10):
data=q.get()
# time.sleep(random.randint(0,1))
print(data,"消费完第%s个数据"%i)
def producer(q):#生产者
for i in range(10):
time.sleep(1)
data="生产第%s个数据"%i
q.put(data)
if __name__=="__main__":
q=Queue()
consu=Process(target=consume,args=(q,))
prod=Process(target=producer,args=(q,))
consu.start()
prod.start()
#在父进程开了一个Queue队列容器,子进程都可以通过get/put方法访问容器,并且不互斥.
# 队列存储/访问顺序是先进先出,后进后出
#生产/消费模型本质就是,开辟一个内存间共享内存空间,有往里写内容,有往外取内容.
```