利用多线程和queue实现生产-消费者模式--消息队列

1、生产者-消费者模式

生产者消费者模式并不是GOF提出的众多模式之一,但它依然是开发同学编程过程中最常用的一种模式,
在这里插入图片描述

生产者模块儿负责产生数据,放入缓冲区,这些数据由另一个消费者模块儿来从缓冲区取出并进行消费者相应的处理。该模式的优点在于:

  • 解耦:缓冲区的存在可以让生产者和消费者降低互相之间的依赖性,一个模块儿代码变化,不会直接影响另一个模块儿
  • 并发:由于缓冲区,生产者和消费者不是直接调用,而是两个独立的并发主体,生产者产生数据之后把它放入缓冲区,就继续生产数据,不依赖消费者的处理速度

该模式常用消息队列来实现:

消息队列是在消息的传输过程中保存消息的容器,消息队列最经典的用法就是消费者 和生产者之间通过消息管道传递消息,消费者和生成者是不同的进程。生产者往管道写消息,消费者从管道中读消息。从而实现解耦和并发

2、多进程模块 multiprocessing

操作系统提供了很多机制来实现进程间的通信,multiprocessing模块提供了Queue和Pipe两种方法来实现,python提供了Queue模块来专门实现消息队列:

  • Queue对象实现一个fifo队列(其他的还有lifo、priority队列)。queue只有gsize一个构造函数,用来指定队列容量,指定为0的时候代表容量无限。主要有以下成员函数:

  • Queue.gsize():返回消息队列的当前空间。返回的值不一定可靠。

  • Queue.empty():判断消息队列是否为空,返回True或者False。同样不可靠

  • Queue.full():判断消息是否满

  • Queue.put(item,block=True,timeout=None):往消息队列中存放数据。block可以控制是否阻塞,timeout控制阻塞时候的等待时间。如果不阻塞或者超时,会引起一个full exception。

  • Queue.put_nowait(item):相当于put(item,False)

  • Queue.get(block=True,timeout=None):获取一个消息,其他等同put

以下两个函数用来判断消息对应的任务是否完成:

  • Queue.task_done():接收消息的线程通过调用这个函来说明消息对应的任务已完成

  • Queue.join():实际上意味着等到队列为空,再执行别的操作

from multiprocessing import Queue, Process
q = Queue() 
q.put(data)  #生产消息
data = q.get() #消费消息

3、使用多线程实现消息队列

生产者函数:

import time
from multiprocessing import Queue, Process  #多进程实现
from threading import Thread  # 多线程实现

class Proceduer(Thread):
    '''定义一个xx队列'''
    def __init__(self,queue):
        super(Proceduer,self).__init__() # 超类 子类继承了父类的所有属性
        self.queue = queue  

    def run(self):
        try:
            for i in range(1,100):
                print("put data is: {0} to queue".format(i))
                self.queue.put(i)
                time.sleep(1)
        except Exception as e :
            print("put data error : %s" %e)
        

消费者函数

# -*- coding:utf-8 -*- 
# author: 使用queue实现多进程生产消费者模式
# data : 2022-11-02


import time
from multiprocessing import Queue, Process  #多进程实现
from threading import Thread  # 多线程实现

from log_send import Proceduer

class Consumer_h3(Thread):
    def __init__(self,queue):
        super(Consumer_h3, self).__init__() 
        self.queue = queue        

    def run(self):
        try:
            while self.queue.empty:
                number = self.queue.get() #取到消息值
                if number %2 != 0:
                    print("get {0} from queue ODD".format(number))
                else:
                    self.queue.put(number)  #将信息放回队列中
            time.sleep(1)
        except Exception as e :
            raise e

class Consumer_top(Thread):
    def __init__(self,queue):
        super(Consumer_top, self).__init__()  # 超类 共享所有的属性
        self.queue = queue        

    def run(self):
        try:
            while self.queue.empty:
                number = self.queue.get() #取到消息值
                if number %2 == 0:
                    print("get {0} from queue top".format(number))
                else:
                    self.queue.put(number)  #将信息放回队列中
            time.sleep(1)
        except Exception as e :
            raise e


def main():
    '''实现一个生产者-消费者队列模式'''
    queues = Queue()  #实例化一个消息队列

    # 实例化生产者,并将消息队列作为参数来提供
    print(" Proceduer start!")
    p = Proceduer(queue = queues)  

    # 实例化消费者,并将消息队列作为参数来提供
    print(" Consumer_h3 start!")
    c1 = Consumer_h3(queue = queues) 
    c2 = Consumer_top(queue = queues)

    # 启动进程去做xx
    c1.start()
    c2.start()
    p.start()

    c1.join()
    c2.join()
    p.join()
    print("All threads terminate!")

if __name__ == "__main__":
    main()

运行结果打印

Proceduer start!
 Consumer_h3 start!
put data is: 1 to queue
get 1 from queue ODD
put data is: 2 to queue
get 2 from queue top
put data is: 3 to queue
get 3 from queue ODD
put data is: 4 to queue
get 4 from queue top
put data is: 5 to queue
get 5 from queue ODD
put data is: 6 to queue
get 6 from queue top
put data is: 7 to queue
get 7 from queue ODD

4、总结

生产者消费者模式也是一种常见的设计模式,而消息队列是较好的实现方式之一,解耦和支持并发,还有其他不同的方式来实现消息队列,后面再继续补充。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
下面是一个使用Python多线程模块实现生产者-消费者模式的示例程序: ```python import threading import time import queue # 生产者线程类 class ProducerThread(threading.Thread): def __init__(self, queue): threading.Thread.__init__(self) self.queue = queue def run(self): for i in range(10): item = "item-" + str(i) self.queue.put(item) print("Produced:", item) time.sleep(1) # 消费者线程类 class ConsumerThread(threading.Thread): def __init__(self, queue): threading.Thread.__init__(self) self.queue = queue def run(self): while True: item = self.queue.get() print("Consumed:", item) time.sleep(2) self.queue.task_done() # 创建一个队列 queue = queue.Queue() # 创建一个生产者线程和一个消费者线程 producer_thread = ProducerThread(queue) consumer_thread = ConsumerThread(queue) # 启动线程 producer_thread.start() consumer_thread.start() # 等待队列被处理完 queue.join() ``` 在这个示例程序中,我们首先定义了一个生产者线程类和一个消费者线程类,分别用于生产和消费数据。然后,我们创建一个队列对象用于存储生产者生产的数据。接着,我们创建一个生产者线程和一个消费者线程,并启动它们。最后,我们使用`queue.join()`方法等待队列被处理完。 需要注意的是,在消费者线程中,我们使用了`queue.task_done()`方法来通知队列已经处理完一个任务。这个方法应该在每次从队列中获取一个任务并处理完之后调用,以便队列能够正确地跟踪任务的状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笨猪起飞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值