生产者——消费者模式(二)

目录

流程图

 ​代码实现

生产者基类——BaseProducer

消费者基类——BaseConsumer

消费者线程封装——ConsumerThread

生产者线程——ProducerThread

消费苹果业务

总结


前面两篇大致介绍了生产者消费者模式及python操作多线程的基本操作,这篇就把两者结合。

上一篇中举例用的苹果id,但是实际生活中,去超市买水果,消费的可能是苹果,也可能是梨,所以单纯生产苹果id就满足不了需求了。我考虑的是封装一个生产者父类及一个消费者父类。生产者父类定义生产消费者对象放入队列的方法,消费者父类定义从队列取出消费对象进行消费,针对不同类型产品子类可继承父类中的方法进行生产消费。除此之外,还对单个生产者线程及消费者线程进行封装,定义这两种不同的线程运行规则,如何进行生产与消费。

流程图

 代码实现

生产者基类——BaseProducer

# coding=utf-8



class BaseProducer(object):
    def get_queue_items(self):
        '''
        @return: 生产者基类,需要字类实现逻辑
        '''
        pass

消费者基类——BaseConsumer

# coding=utf-8


class BaseConsumer(object):

    def __init__(self):
        # 消费者线程名称
        self.consumer_thread_name = ' '

    def action(self):
        pass

消费者线程封装——ConsumerThread

由于生产者线程初始化的时候会初始化消费者线程,所以先封装消费者线程
# coding=utf-8
import threading
class ConsumerThread(threading.Thread):
    def __init__(self, queue, consumer_thread_name, consumer_sleep_time):
        '''

        @param queue: 生产者初始化的队列
        @param consumer_thread_name: 消费者线程名称
        @param consumer_sleep_time: 消费者等待实践
        '''
        # 初始化线程
        super(self.__class__, self).__init__()
        self.queue = queue
        self.name = consumer_thread_name
        self.consumer_sleep_time = consumer_sleep_time


    def run(self):
        '''
        从队列中取出消费对象,并调用消费对象方法action进行消费
        '''
        while True:
            consumer = self.queue.get()
            # 将当前线程名称与消费者对象绑定
            consumer.consumer_thread_name = self.name
            print("消费线程是:%s" % consumer.consumer_thread_name)
            consumer.action()
            self.queue.task_done()

生产者线程——ProducerThread

# coding=utf-8
from demo.base_producer import BaseProducer
from demo.consumer_thread import ConsumerThread
import threading
import time
class ProducerThread(threading.Thread):
    '''
    生产者线程
    '''
    def __init__(self, queue, producer_thread_name, producer, consumer_maxnum, producer_sleep_time,consumer_sleep_time):
        '''
        @param queue: 队列对象
        @param producer_thread_name: 队列名称
        @param producer: 生产者实例对象
        @param consumer_num: 消费者最大线程数
        @param producer_sleep_time:生产间隔
        @param consumer_sleep_time:消费间隔
        '''
        # 初始化线程
        super(self.__class__, self).__init__()
        self.queue = queue
        self.producer_thread_name = producer_thread_name
        self.producer = producer
        self.consumer_maxnum = consumer_maxnum
        self.producer_sleep_time = producer_sleep_time
        self.consumer_sleep_time = consumer_sleep_time

        # 如果初始化出来的对象不是Producer类,则抛出异常
        if not isinstance(producer, BaseProducer):
            raise Exception("%s is not ProducerAction instance" % producer)

        print("init producer_%s"%producer_thread_name)

    def run(self):
        # 定义一个列表,用来装生产出来的消费对象
        item_list = []
        while True:
            # 如果列表中中消费对象全部进入队列中,则重新开始生产

            if len(item_list)==0:
                print("列表消费者对象为空,开始生产消费对象")
                item_list = self.producer.get_queue_items()
            # 记录生产的消费对象数量
            total_num = len(item_list)
            while True:
                # 如果队列为空,则跳出循环
                if len(item_list)==0:
                    break

                # 当队列中未取出的消费行为对象数量小于等于消费对象最大数量,则添加入队列
                if self.queue.unfinished_tasks <= self.consumer_maxnum:
                    # 列表中弹出一个消费对象
                    consumer_tmp = item_list.pop()
                    # 加入队列
                    self.queue.put(consumer_tmp)

                # 生产每个消费对象之间的间隔
                time.sleep(self.producer_sleep_time)

    def start_work(self):
        '''
        生产者开始工作
        '''
        # 根据最大消费对象线程数量创建消费对象
        for i in range(1,self.consumer_maxnum+1):
            print("init and start consumer_%s%d" % (self.producer_thread_name, i))
            # 创建消费对象线程
            consumer = ConsumerThread(self.queue, "%s_%d"%(self.producer_thread_name,i), self.consumer_sleep_time)
            # 开始消费
            consumer.start()


        self.start()

消费苹果业务

# coding=utf-8
from demo.base_producer import BaseProducer
from demo.base_consumer import BaseConsumer
from demo.producer_thread import ProducerThread
import queue
class AppleProducer(BaseProducer):
    def get_queue_items(self):
        # 一次生产10个消费对象,返回列表
        consumer_list = []
        for i in range(1,11):
            consumer = AppleConsumer("apple_id_%d"%i)
            consumer_list.append(consumer)
        return consumer_list



class AppleConsumer(BaseConsumer):
    def __init__(self,apple_id):
        super(self.__class__, self).__init__()
        self.apple_id = apple_id

    def action(self):
        print("消费的苹果是:%s"%self.apple_id)



if __name__ == "__main__":
    # 初始化生产者对象
    producer = AppleProducer()

    queue = queue.Queue()

    producer_thread = ProducerThread(queue, "apple_thread", producer, 5, 0.1, 1)

    producer_thread.start_work()

结果

从结果来看,先初始化了一个苹果生产者线程,接着生产线程里初始化了5个消费线程,然后生产线程生产了10个消费对象放列表并添加到队列,5个消费线程分别取消费对象进行消费,当生产的列表中对象个数为0时,重新开始生产消费对象。

总结

主业务可以自己写好自定义的Producer和Consumer,然后放到线程中。后续可以在多台机器上跑多个生产线程,队列用mysql或者redis代替。

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于CPU多核编程——线程池开发方面的问题,我可以向您提供一些建议和思路。 线程池是一种常用的并发编程技术,其主要作用是在多核CPU的情况下,实现任务的并行执行,提高程序的性能。在实际开发中,线程池通常都采用生产者-消费者模式进行开发。 具体来说,线程池中有一个任务队列,负责存放待执行的任务。线程池内部有一些工作线程,它们会不断地从任务队列中取出任务进行执行。如果任务队列为空,那么工作线程会被挂起,等待新的任务到来。 在开发线程池时,关键是要实现线程的管理和同步。具体工作包括: 1. 配置线程池中工作线程的数量。这个数量通常要根据CPU的核心数和任务的类型来决定。如果任务是I/O密集型,那么工作线程数量应该设置得比较大;如果任务是计算密集型,那么工作线程数量可以适当减少。 2. 实现任务队列。这个队列可以采用多种数据结构来实现,比如数组、链表、堆等。对于多线程的情况,需要考虑线程之间的同步问题,防止数据竞争。 3. 实现工作线程。这些线程需要不断地从任务队列中取出任务进行执行,并且在没有任务时进入等待状态。同时,为了保证线程之间的公平性,需要采用一些调度算法,比如轮询、优先级队列等。 4. 实现任务接口。这些接口需要包括任务的执行函数以及相关的参数,以支持不同类型的任务。 总体来说,线程池的开发比较复杂,需要在多线程的情况下考虑到各种同步和调度问题。但是一旦实现成功,线程池可以大大提高程序的运行效率和响应速度。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值