Coding-生产者消费者

并发编程经典问题之生产者消费者。本文简单介绍了问题模型,并提供了一种 Python3 的解决方式。

问题模型
  • 问题描述:
    • 生产者-消费者模型描述的是有一群生产者进程在生产产品,并将这些产品提供给消费者进程并发进行,具备并发程序的典型特征。
    • 为使生产者进程和消费者进程并发进行,在它们之间设置一个具有多个缓冲区的缓冲池,生产者进程可以将其所生产的产品放入一个缓冲区中,消费者进程可以从一个缓冲区中取得产品去消费。
  • 问题分析:
    • 所有的生产者进程和消费者进程的工作互相独立,是以异步方式运行的。
    • 产者和消费者又是一个相互协作的关系,只有生产者生产之后,消费者才能消费,他们也是同步关系。
Talk is cheap, show me code
  • 各种情况:
    • 多个生产者,一个消费者:例如日志记录,产生日志的线程(进程)会有很多,但是真正写日志文件的线程(进程)只能有一个;
    • 一个生产者,多个消费者:例如任务分发,接收任务只需要一个线程(进程),但是执行任务需要多个线程(进程)并发执行;
    • 多个生产者,多个消费者。
  • 以一个生产者,多个消费者为例,使用线程安全的queue.Queue作为缓冲区来实现
  • queue 模块实现多生产者,多消费者队列。当信息必须安全的在多线程之间交换时,它在线程编程中是特别有用的。此模块中的 Queue 类实现了所有锁定需求的语义。
  • queue 依赖于 Python 支持的线程可用性。
  • queue 模块实现了三种类型的队列,它们的区别仅仅是条目取回的顺序:
    • 在 FIFO 队列(Queue)中,先添加的任务先取回;
    • 在 LIFO 队列(LifoQueue)中,最近被添加的条目先取回 (操作类似一个堆栈);
    • 优先级队列(PriorityQueue)中,条目将保持排序(使用 heapq 模块)并且最小值的条目第一个返回。
from threading import Thread,current_thread
from queue import Queue
from time import sleep
from random import randint

PARALLEL_NUM = 5
MAX_WEIGHT = 4

# 任务类
class Task():
    __uid = 0
    __weight = 0
    def __init__(self, version, weight):
        self.__uid = version*100 + weight
        self.__weight = weight
    
    def __str__(self):
        return str(self.__uid)   

    def run(self):
        sleep(self.__weight)
    
# 生产者
def producer(q):
    th = current_thread()
    print("Producer[" + th.name + "] Started")
    version = 1
    sleep(1)
    # 开始工作
    while True:
        batch = randint(1, MAX_WEIGHT)
        print("producer put batch: " + str(version*100 + batch))    # 汇报版本信息
        for weight in range(1, batch+1):
            q.put(Task(version, weight))
        sleep(1)
        version += 1
    
# 消费者
def consumer(q):
    th = current_thread()
    print("Consumer[" + th.name + "] Started")
    sleep(1)
    # 开始工作
    while True:
        task = q.get()  # 获取任务
        task.run()      # 执行任务
        print(th.name + " finish task: " + str(task)) # 汇报结果

def main():
    # 初始化队列
    q = Queue(maxsize=100)
    
    # 启动生产者线程
    thread_producer = Thread(target=producer, args=(q,), daemon=True)
    thread_producer.start()
    
    # 启动消费者线程
    thread_consumers = []
    for i in range(PARALLEL_NUM):
        thread_consumers.append(Thread(target=consumer, args=(q,), daemon=True))
        thread_consumers[-1].start()
    input("\n\n==Enter Any Key To Exit==\n\n")

if __name__ == '__main__':
    main() 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值