python 21 队列数据共享、消费者模型

day 21 队列数据共享、消费者模型

昨日回顾

1.进程调度算法
	-先来先服务
	-短作业优先
	-时间片轮转
	-多级反馈队列

2.同步、异步、阻塞、非阻塞
	-同步和异步:指的是回调方式,如果有回调就是异步,如果等待就是同步
	-阻塞和非阻塞:指的是等待消息结果时的状态,如果在过程中,干了别的事,就是非阻塞,如果一直等,则是阻塞
	3.进程Process类,实例化的时候得参数
		-target:要执行的任务
		-args:以位置参数传给任务传值
		-kwargs:以关键字给任务传值
		-name:进程名字(如果不写,会有个默认名字)
4.进程对象的属性和方法
	-属性
		-name
		-pid:进程的id号,如果没有这个对象,需要借助os.getpid(),os.getppid()
		-daemon:守护进程,如果设置为True,主进程挂了,该子进程也会挂。需要在p.start()之前执行
	-方法
		-is_alive() 进程是否存活
		-terminate() 杀死该进程
		-join() 主进程等待子进程结束后才继续执行-start() 子进程要执行必须调用
		-run() 真正的任务
5.开启进程的另一种方式(类的继承)
	写一个类,继承Process类
	重写run方法,里面可以加入自己的任务
	实例化得到写的类,调用这个类对象的start()方法

进程间数据是隔离的
6.进程锁
	-多个进程操作同一个数据(文件中的数据,而不是内存中的数据)
	-lock=Lock()
	-加锁:lock.acquire()
	-解锁:lock.release()

近日内容

1.进程Queue介绍

1.进程间数据隔离,两个进程进行通信,借助于Queue
2.进程间通信叫ipc:inter_Process Communication
	-借助于Queue实现进程间通信
	-借助于文件
	-借助于数据库
	-结束语消息队列:rabbitmq,kafka

基本使用

from multiprocessing import Process, Queue


if __name__ == '__main__':
    # maxsize表示Queue的大小是多少,能放多少东西
    queue = Queue(3)  # 队列先进先出
    # 放数据
    queue.put("lem")
    queue.put("lam")
    queue.put("emt")
    
'''
# 实例化得到一个对象,数字表示queue的大小
queue=Queue(3)
# 放值
# block:是否阻塞
# timeout:等待时间
queue.put()
# 取值
queue.get()

不等待
queue.put_nowait()
queue.put_nowait()
# 
queue.full()
queue.empty()
 '''

2.通过Queue实现进程间通信

from multiprocessing import Process, Queue
import os
import time


def task(queue):
    print(f"此进程{os.getpid()}开始放数据了")
    time.sleep(10)
    queue.put("lem is my wife")
    print(f"此进程{os.getpid()}放完了")

if __name__ == '__main__':
    # 不写数字,表示可以任意长度
    queue = Queue()
    p = Process(target=task, args=(queue,))
    p.start()

    res = queue.get()  # 会卡在这
    print(res)

3.批量生产数据放入Queue再批量取出

from multiprocessing import Process, Queue
import os
import time

def get_task(queue):
    res = queue.get()
    print(f"{os.getpid()}:这个进程去了这个数据{res}")

def put_task(queue):
    queue.put(f"{os.getpid()}:放的数据")
    # print(f"{os.getpid()}:放了数据")

if __name__ == '__main__':

    queue = Queue(1)
    p1 = Process(target=put_task, args=(queue,))
    p2 = Process(target=put_task, args=(queue,))
    p1.start()
    p2.start()

    p3 = Process(target=get_task, args=(queue,))
    p4 = Process(target=get_task, args=(queue,))
    p3.start()
    p4.start()

4.生产者消费者模型(重点)

from multiprocessing import Process, Queue
import os
import random
import time

# def producer(queue):
#     # 生产的东西放到queue中
#     for i in range(10):
#         msg = f"{os.getpid()}这个厨师蒸了第{i+1}个包子"
#         print(msg)
#         # 模拟一下延迟
#         time.sleep(random.randint(1,3))
#         queue.put(f"第{i+1}个包子")
#
#
# def consumer(queue):
#     # 消费者从queue中取数据消费(吃包子)
#     while True:
#         res = queue.get()
#         # 模拟一下延迟
#         time.sleep(random.randint(1,3))
#         print(f"{os.getpid()}这个消费者,吃了{res}")
#
#
#
# if __name__ == '__main__':
#     queue = Queue()
#
#     p1 = Process(target=producer, args=(queue,))
#     p1.start()
#
#     p2 = Process(target=consumer, args=(queue,))
#     p2.start()


'===================================='

# # 改良(生产者已经)
#
# def producer(queue):
#     # 生产的东西放到queue中
#     for i in range(10):
#         msg = f"{os.getpid()}这个厨师蒸了第{i + 1}个包子"
#         print(msg)
#         # 模拟一下延迟
#         time.sleep(random.randint(1, 3))
#         queue.put(f"第{i + 1}个包子")
#     queue.put(None)
#
#
# def consumer(queue):
#     # 消费者从queue中取数据消费(吃包子)
#     while True:
#         res = queue.get()
#         if not res: break  # 如果取到None,说明打烊了(生产者不生产了),退出
#         # 模拟一下延迟
#         time.sleep(random.randint(1, 3))
#         print(f"{os.getpid()}这个消费者,吃了{res}")
#
#
# if __name__ == '__main__':
#     queue = Queue()
#
#     p1 = Process(target=producer, args=(queue,))
#     p1.start()
#
#     p2 = Process(target=consumer, args=(queue,))
#     p2.start()


# "===================================================="
# # 把put None放在主进程中执行
#
# def producer(queue):
#     # 生产的东西放到queue中
#     for i in range(10):
#         msg = f"{os.getpid()}这个厨师蒸了第{i + 1}个包子"
#         print(msg)
#         # 模拟一下延迟
#         time.sleep(random.randint(1, 3))
#         queue.put(f"第{i + 1}个包子")
#
#
#
# def consumer(queue):
#     # 消费者从queue中取数据消费(吃包子)
#     while True:
#         res = queue.get()
#         if not res: break  # 如果取到None,说明打烊了(生产者不生产了),退出
#         # 模拟一下延迟
#         time.sleep(random.randint(1, 3))
#         print(f"{os.getpid()}这个消费者,吃了{res}")
#
#
# if __name__ == '__main__':
#     queue = Queue(3)
#
#     p1 = Process(target=producer, args=(queue,))
#     p1.start()
#
#     p2 = Process(target=consumer, args=(queue,))
#     p2.start()
#
#     # 如果把put None放在这,会有问题
#     # 主进程会先执行这句话,消费者进程读到None,直接结束,生产者进程没有结束,于是生产者一直生产,消费者不消费
#     # 直到Queue满了就一直卡在这
#     p1.join()
#     queue.put(None)


5.多个生产者多个消费者的生产者消费者模型

"===================================================="


# 把put None放在主进程中执行

# def producer(queue, food):
#     # 生产的东西放到queue中
#     for i in range(10):
#         msg = f"{os.getpid()}这个厨师做了第{i + 1}个{food}"
#         print(msg)
#         # 模拟一下延迟
#         time.sleep(random.randint(1, 3))
#         queue.put(f"第{i + 1}个{food}")
#
#
# def consumer(queue):
#     # 消费者从queue中取数据消费(吃包子)
#     while True:
#         res = queue.get()
#         if not res: break  # 如果取到None,说明打烊了(生产者不生产了),退出
#         # 模拟一下延迟
#         time.sleep(random.randint(1, 3))
#         print(f"{os.getpid()}这个消费者,吃了{res}")
#
#
# if __name__ == '__main__':
#     queue = Queue(3)
#     # 起了三个生产者
#     p1 = Process(target=producer, args=(queue, "包子"))
#     p2 = Process(target=producer, args=(queue, "蛋糕"))
#     p3 = Process(target=producer, args=(queue, "饼"))
#     p1.start()
#     p2.start()
#     p3.start()
#
#     # 起两个消费者
#     c1 = Process(target=consumer, args=(queue,))
#     c2 = Process(target=consumer, args=(queue,))
#     c1.start()
#     c2.start()
#
#     # 等三个生产者都生产完,放三个None
#     p1.join()
#     p2.join()
#     p3.join()
#     queue.put(None)
#     queue.put(None)
#     queue.put(None)


# 如果消费者多,则多出来的会挂者

def producer(queue, food, name):
    # 生产的东西放到queue中
    for i in range(10):
        msg = f"{name}这个厨师做了第{i + 1}个{food}"
        print(msg)
        # 模拟一下延迟
        time.sleep(random.randint(1, 3))
        queue.put(f"第{i + 1}个{food}")


def consumer(queue, name):
    # 消费者从queue中取数据消费(吃包子)

    while True:
        try:
            # 模拟一下延迟
            time.sleep(random.randint(1, 3))
            res = queue.get(timeout=20)
            print(f"{name}这个消费者,吃了{res}")
        except Exception as e:
            print(e)
            break


if __name__ == '__main__':
    queue = Queue(3)
    # 起了三个生产者
    p1 = Process(target=producer, args=(queue, "包子", "rui"))
    p2 = Process(target=producer, args=(queue, "蛋糕", "lem"))
    p3 = Process(target=producer, args=(queue, "饼", "hina"))
    p1.start()
    p2.start()
    p3.start()

    # 起两个消费者
    c1 = Process(target=consumer, args=(queue, "吃货1"))
    c2 = Process(target=consumer, args=(queue, "吃货2"))
    c1.start()
    c2.start()

6.进程间数据共享(了解)

from multiprocessing import Process,Manager,Lock

# 魔法方法:类内以__开头__结尾的方法,都叫魔法方法,某种情况下会触发它的执行
'''
__init__ :类()触发
__new__:
__getattr__
__setattr__
__getitem__
__setitem__

'''

# def task(dic,lock):
#     # lock.acquire()
#     # dic['count']-=1
#     # lock.release()
#     with lock:
#         dic['count'] -= 1
#
# if __name__ == '__main__':
#     lock = Lock()
#     with Manager() as m:
#         # 如果直接定义dict,这个dict在多个进程中其实是多份,进程如果改,只改了自己的
#         #如果定义的是m.dict({'count': 100}),多个进程之间就可以共享这个数据
#         dic = m.dict({'count': 100})
#
#         p_l = []
#         for i in range(100):
#             p = Process(target=task, args=(dic, lock))
#             p_l.append(p)
#             p.start()
#         for p in p_l:
#             p.join()





def task(dic,lock):
    with lock:
        dic['count'] -= 1

if __name__ == '__main__':
    lock = Lock()
    dic={'count':100}
    p_l = []
    for i in range(100):
        p = Process(target=task, args=(dic, lock))
        p_l.append(p)
        p.start()
    for p in p_l:
        p.join()



    print(dic)

7.线程概念

如果把我们上课的过程看成一个进程的话,那么我们要做的是耳朵听老师讲课,手上还要记笔记,脑子还要思考问题,这样才能高效的完成听课的任务。而如果只提供进程这个机制的话,上面这三件事将不能同时执行,同一时间只能做一件事,听的时候就不能记笔记,也不能用脑子思考,这是其一;如果老师在黑板上写演算过程,我们开始记笔记,而老师突然有一步推不下去了,阻塞住了,他在那边思考着,而我们呢,也不能干其他事,即使你想趁此时思考一下刚才没听懂的一个问题都不行,这是其二


#进程是资源分配的最小单位,线程是CPU调度的最小单位。每一个进程中至少有一个线程。

from threading import Thread
from queue import Queue
import os
import time


def task():
    time.sleep(3)
    print('我是子线程执行的')
    print(os.getpid())


if __name__ == '__main__':
    # 启动线程

    ctime = time.time()
    t = Thread(target=task)
    t.start()
    # task()
    time.sleep(3)
    print(os.getpid())
    print(time.time() - ctime)

作业

1.基于进程写生产者消费模型
def producer(queue, name, food):
    for i in range(10):
        print(f"{name}做了第{i + 1}个{food}")
        time.sleep(random.randint(1, 3))
        queue.put(f"第{i + 1}个包子")


def consumer(queue, name):
    while True:
        try:
            res = queue.get(timeout=10)
            time.sleep(random.randint(1, 3))
            print(f"{name}吃了{res}")
        except Exception as e:
            print(e)
            break


if __name__ == '__main__':
    queue = Queue(3)
    p1 = Process(target=producer, args=(queue, "lem", "包子"))
    p2 = Process(target=producer, args=(queue, "hina", "蛋糕"))
    p3 = Process(target=producer, args=(queue, "rui", "大饼"))
    p1.start()
    p2.start()
    p3.start()

    c1 = Process(target=consumer, args=(queue, "吃货1"))
    c2 = Process(target=consumer, args=(queue, "吃货x"))
    c1.start()
    c2.start()
2.开启5个进程,执行1加到10000
5000050000
5000050000
5000050000
5000050000
5000050000
0.7479662895202637
3.开启5个线程,执行1加到100000
5000050000
5000050000
5000050000
5000050000
5000050000
0.0359036922454834
4.打印出上面两个的执行时间,比较进程快还是线程快(计算进程快,io线程快)
posted @ 2021-04-26 15:43  橘丶阳菜  阅读(104)  评论(0编辑  收藏  举报