python之路---并发编程之进程&生产者与消费者模型

三个关键词:消费者/生产者/模型

模型:可以理解为用于解决一类问题的统一方法/模板

生产者:比喻的是在程序中负责产生数据的任务

消费者:比喻的是在程序中负责处理数据的任务

实现

生产者 ------> queue < ------ 消费者 (通过队列进行交互,实现解耦和)

好处

实现了生产者与消费者的解耦和,生产者可以不断的生产,消费者可以不断的消费,平衡了生产者的生产能力与消费者的消费能力,从而提升了程序的整体运行效率

什么时候使用该模型

当程序中明显的出现了两类任务,一类负责产生数据,一类负责处理数据,就可以使用生产者与消费者模型来提升程序的整体效率

生产者与消费者模型的使用

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


def produce(q):
    for i in range(1, 5):
        res = '包子%s' % i
        time.sleep(random.uniform(1, 3))
        q.put(res)
        print('厨师:%s生产了%s' % (os.getpid(), res))


def customer(q):
    while True:
        res = q.get()
        time.sleep(random.uniform(1, 3))
        print('客户:%s吃了包子%s' % (os.getpid(), res))


if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=produce, args=(q,))
    c1 = Process(target=customer, args=(q,))
    p1.start()
    c1.start()

    print('主进程 is done')

执行上诉代码,发现一个问题,当队列内的数据取空后(生产者生产完毕),消费者的get操作发生了阻塞,所以要寻求一种方法让消费者知道生产者生产完毕

import time
import random
from multiprocessing import Process,Queue


def produce(name,food,q):
    for i in range(1,4):
        res = '%s%s'%(food,i)
        time.sleep(random.uniform(1,3))
        q.put(res)
        print('\033[45m厨师%s生产了%s%s\033[0m'%(name,food,i))


def customer(name,q):
    while True:
        res = q.get()
        if res is None:
            break
        time.sleep(random.uniform(1,3))
        print('\033[46m%s 吃了 %s\033[0m'%(name,res))


if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=produce,args=('bob','包子',q))
    p2 = Process(target=produce,args=('tom','馒头',q))
    p3 = Process(target=produce,args=('tony','花卷',q))

    c1 = Process(target=customer,args=('顾客1',q))
    c2 = Process(target=customer,args=('顾客1',q))

    p1.start()
    p2.start()
    p3.start()

    c1.start()
    c2.start()

    p1.join()
    p2.join()
    p3.join()
    q.put(None)
    q.put(None)
    print('主进程 is done')

3个join之后意味着生产者生产完毕,由主进程为队列添加结束信号(也可以在生产者内添加),消费者拿到结束信号后结束

但是这种方法需要有几个消费者就发送几个信号(消费者个数无法预知,这种做法也low)

另一种队列:JoinableQueue([maxsize])  # maxsize为允许队列存放的最大数,默认无限制

方法

1.拥有与Queue对象相同的方法

2.task_done().消费者调用该方法,记录get()方法的返回项已经被处理

3.join().调用此方法发生阻塞,直到队列中的内容全部被取干净

import time
import random
from multiprocessing import Process,JoinableQueue


def produce(name,food,q):
    for i in range(1,4):
        res = '%s%s'%(food,i)
        time.sleep(random.uniform(1,3))
        q.put(res)
        print('\033[45m厨师%s生产了%s%s\033[0m'%(name,food,i))


def customer(name,q):
    while True:
        res = q.get()
        time.sleep(random.uniform(1,3))
        print('\033[46m%s 吃了 %s\033[0m'%(name,res))
        q.task_done()


if __name__ == '__main__':
    q = JoinableQueue()
    p1 = Process(target=produce,args=('bob','包子',q))
    p2 = Process(target=produce,args=('tom','馒头',q))
    p3 = Process(target=produce,args=('tony','花卷',q))

    c1 = Process(target=customer,args=('顾客1',q))
    c2 = Process(target=customer,args=('顾客1',q))

    c1.daemon = True
    c2.daemon = True
    p1.start()
    p2.start()
    p3.start()

    c1.start()
    c2.start()

    p1.join()
    p2.join()
    p3.join()
    '''
    让父进程等待生产者进程执行完毕后再执行
    q.join执行结束意味着--->生产者代码执行完毕
    '''

    q.join()
    '''
    等待队列被取干净
    执行结束意味着父进程代码执行结束,生产者执行结束并且队列被取干净--->消费者没有存在的意义
    即,这种情况下,消费者代码应该伴随着父进程代码的结束而结束(守护进程)
    '''


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值