Python--day35(守护进程,互斥锁、IPC、生产者消费者模型)

1. 守护进程(daemon)

什么是守护进程:一个进程可以守护另一个进程。开启守护进程是为了并发执行某个任务,但这个任务如果伴随着主进程的结束而没有存在的意义,就可以将子进程设为守护进程。

如果b是a的守护进程,a是被守护的进程,如果a挂了,则b也随之结束

比如:qq接收到一个视频文件,于是开启了一个子进程来下载,如果中途退出了,下载任务就没必要继续下去

import time
from multiprocessing import Process

def task():
    print("妃子进宫了")
    time.sleep(50)
    print("妃子挂了")

if __name__ == '__main__':

    print("皇帝登基了")
    p = Process(target=task)
    p.daemon = True
    p.start()
    time.sleep(3)
    print("皇帝驾崩了")
View Code

2. 互斥锁

2.1 什么是互斥锁

出现原因:并发将带来资源的竞争问题,当多个进程要操作同一个资源时,会导致数据错乱的问题

互斥锁:互相排斥的锁,如果这个资源被别人占用,或者说锁了,其他进程就无法使用

【注意】锁 并不是真的把资源锁起来,只是在代码层面上限制了代码不能正常进行

2.2 使用方法

import time
import random
from multiprocessing import Process,Lock

def task1(lock):
    # 要开始使用了 上锁
    lock.acquire()
    print("123")
    time.sleep(random.randint(1,2))
    print("456")
    time.sleep(random.randint(1, 2))
    print("789")
    # 用完了就解锁
    lock.release()
    # 注意注意:  不要对同一把执行多出acquire 会锁死导致程序无法执行  一次acquire必须对应一次release

def task2(lock):
    lock.acquire()
    print("qwe")
    time.sleep(random.randint(1, 2))
    print("rty")
    time.sleep(random.randint(1, 2))
    print("uio")
    lock.release()

def task3(lock):
    lock.acquire()
    print("asd")
    time.sleep(random.randint(1, 2))
    print("fgh")
    time.sleep(random.randint(1, 2))
    print("jkl")
    lock.release()

if __name__ == '__main__':
    lock = Lock()
    # 想要保住数据安全,必须保住所有进程使用同一把锁,把这一行提到if之外,虽然每次导入
    # 都会重新导入并执行,但是子进程一开始就确定了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()

from multiprocessing import Process,Lock
def task1(lock):
    lock.acquire()
    print("qwertyui")
    lock.release()


def task2(lock):
    lock.acquire()
    print("asddfghj")
    lock.release()


def task3(lock):
    lock.acquire()
    print("zxcvbnm")
    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()
View Code

2.3 互斥锁与join的区别

大前提:两者的本质原理都一样,都是将并发编程穿行,从而保证有序

区别:

1. join是固定了执行顺序,会造成父进程等待子进程,锁依然是公平竞争,谁先抢到谁先执行,不影响父进程做其他事

2. join是把进程的任务全部串行,锁可以锁住任意代码,一行也可以,可以自己调整粒度。

粒度越大,效率越低,粒度越小,效率越高

3. 共享内存方式

3.1 IPC(进程间通信Manager)

进程之间相互隔离,当一个进程想要把数据给另一个进程,就要考虑IPC

进程间通信的方式:

1. 管道:只能单向通讯,数据都是二进制

2. 文件:在硬盘上创建共享文件,

  缺点:速度快

  优点:数据量几乎没有限制

3. socket:编程复杂度较高

4. 共享内存:必须要操作系统来分配

  优点:速度快

  缺点:数据量不能太大

import random
import time

from multiprocessing import Process,Lock,Manager

def task(data, lock):
    lock.acquire()
    # print(data)
    num = data["num"]
    time.sleep(0.1)
    data["num"] = num - 1
    lock.release()


if __name__ == '__main__':
    lock = Lock()
    m = Manager()

    data = m.dict({"num": 10})

    for i in range(10):
        p = Process(target=task, args=(data, lock))
        p.start()

    time.sleep(2)
    print(data)
View Code

3.2 Queue队列

队列:是一种特殊的数据结构,先存储的先取出 就像排队 先进先出

堆栈:先存储的后取出, 就像衣柜 桶装薯片 先进后出

扩展:函数嵌套调用时 执行顺序是先进后出 也称之为函数栈

调用 函数时 函数入栈 函数结束就出栈

from multiprocessing import Queue

q = Queue(3)    # 建队列  不指定maxsize 则没有数量限制
q.put(1)
q.put(2)
q.put(3)
print(q.get())   # 1
q.put(4)    # 如果容量已经满了,在调用put时将进入阻塞状态 直到有人从队列中拿走数据有空位置 才会继续执行

print(q.get())
print(q.get())
print(q.get())
print(q.get())    # 如果队列已经空了,在调用get时将进入阻塞状态 直到有人从存储了新的数据到队列中 才会继续

#block 表示是否阻塞 默认是阻塞的   # 当设置为False 并且队列为空时 抛出异常
q.get(block=True,timeout=2)
# block 表示是否阻塞 默认是阻塞的   # 当设置为False 并且队列满了时 抛出异常
# q.put("123",block=False,)
# timeout 表示阻塞的超时时间 ,超过时间还是没有值或还是没位置则抛出异常  仅在block为True有效
View Code

4. 生产者消费者模型

4.1 消费者生产者模型是什么

模型:就是解决某个问题套路

  产生数据的一方称之为生产者

  处理数据的一方称之为消费者

例如: 爬虫 生活中到处都是这种模型

  饭店 厨师就是生产者 你吃饭的人就是消费者

 

4.2 解决什么问题

生产者和消费,处理速度不平衡,一方快一方慢,导致一方需要等待另一方

 

4.3 怎么解决

原本,双方是耦合 在一起,消费着必须等待生产者生成完毕在开始处理, 反过来

如果消费消费速度太慢,生产者必须等待其处理完毕才能开始生成下一个数据

 

思路:

将双方分开来.一专门负责生成,一方专门负责处理

这样一来数据就不能直接交互了 双方需要一个共同的容器

生产者完成后放入容器,消费者从容器中取出数据

这样就解决了双发能力不平衡的问题,做的快的一方可以继续做,不需要等待另一方

import time
import random
from multiprocessing import Process,Queue
def task1(q):
    for i in range(10):
        time.sleep(random.randint(0, 2))
        print("正在烧%s盘菜" % i)

        rose = "%s盘菜" % i
        q.put(rose)


def task2(q):
    for i in range(10):
        rose = q.get()
        print(rose,"正在消费")
        time.sleep(random.randint(0, 2))
        print(rose,"消费完成")


if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=task1, args=(q,))
    p2 = Process(target=task2, args=(q,))
    p1.start()
    p2.start()
View Code

 

 

 

猜你喜欢

转载自www.cnblogs.com/wangyong123/p/10967938.html
今日推荐