Python Day 36:JoinableQueue队列/线程/线程互斥锁/死锁/递归锁/信号量

## 守护进程

```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方法访问容器,并且不互斥.
# 队列存储/访问顺序是先进先出,后进后出
#生产/消费模型本质就是,开辟一个内存间共享内存空间,有往里写内容,有往外取内容.

```

猜你喜欢

转载自www.cnblogs.com/huhongpeng/p/10994380.html