python程序设计:多线程与多进程编程

1、题目要求

用python编写程序实现多个生产者,多个消费者和多个缓冲区的同步问题,并且生产者的生产速度大于消费者的消费速度

2、不专业讲解

  • 这里的缓存区其实就是使用了多个队列,生产者即往队列放入数据,消费者则删除队列的数据。
  • 生产者类class Producer(threading.Thread)和消费者类class Consumer(threading.Thread)的定义表明,Producer和Consumer都继承自 threading.Thread,即可以使用多线程方法。
  • 在创建线程的时候,会自动执行__init__()初始化方法, 当我们执行线程的start()方法会执行run()方法。join()方法会堵塞主线程,等待线程执行完毕后才放行。
  • threading.Event()是threading提供的机制类似于一个线程向其它多个线程发号施令的模式,Event为False,会堵塞线程(执行clear()方法),Event为True,会开放线程(执行set()方法)。

3、代码

#!/usr/bin/python

import queue
import random
import threading


# 定义最大线程数常量
THREAD_MAX_NUM = 5
# 定义每个队列长度常量
QUEUE_MAX_SIZE = 10
# 定义缓冲区数量常量
BUFFER_MAX = 3
# 定义全局缓存区
queue_list = []


# 生产者
class Producer(threading.Thread):
    def __init__(self, name, thread_event, num, buffer_index):
        threading.Thread.__init__(self)
        self.name = "生产者" + str(name)
        self.queue = queue_list[buffer_index]
        self.event = thread_event
        self.num = num
        self.str_index = " 在缓存区" + str(buffer_index)
        self.count = 0

    def run(self):
        while self.count < self.num:
            # 判断栈是否已经满
            if self.queue.full():
                # 栈满 线程进入等待
                self.event.wait()
                # 线程唤醒后将flag设置为False
                if self.event.isSet():
                    self.event.clear()
            else:
                self.event.set()
                # 向栈添加数据
                data = random.randint(0, 5000)
                self.queue.put(data)
                print(self.name + self.str_index + " 生产数据 " + str(data) + '\n')

            self.count += 1


# 消费者
class Consumer(threading.Thread):
    def __init__(self, name, thread_event, thread_lock, num, buffer_index):
        threading.Thread.__init__(self)
        self.name = "消费者" + str(name)
        self.queue = queue_list[buffer_index]
        self.event = thread_event
        self.lock = thread_lock
        self.num = num
        self.str_index = " 在缓存区" + str(buffer_index)
        self.count = 0

    def run(self):
        while self.count < self.num:
            # 判断栈是否为空
            if self.queue.empty():
                # 栈空 线程进入等待
                self.event.wait()
                # 线程唤醒后将flag设置为False
                if self.event.isSet():
                    self.event.clear()
            else:
                self.event.set()
                # 向栈消耗数据
                self.lock.acquire()
                data = self.queue.get()
                self.queue.task_done()
                self.lock.release()
                print(self.name + self.str_index + " 消费数据 " + str(data) + '\n')

            self.count += 1


if __name__ == '__main__':
    # 创建缓冲区
    for i in range(BUFFER_MAX):
        queue_list.append(queue.Queue(maxsize=QUEUE_MAX_SIZE))

    event = threading.Event()
    lock = threading.Lock()
    threads = []
    # 创建线程
    for i in range(THREAD_MAX_NUM):
    	# 生成不大于缓冲区数量的的随机数字(随机在某个缓冲区生产或消费数据)
        index = random.randint(0, len(queue_list) - 1)
        # 创建 生产者和消费者 线程
        threads.append(Producer(i, event, QUEUE_MAX_SIZE, index))
        threads.append(Consumer(i, event, lock, QUEUE_MAX_SIZE, index))

    # 开始所有线程
    for t in threads:
        t.start()

    # 等待所有线程完成
    for t in threads:
        t.join()

     # 查看缓存区情况
    for i in range(BUFFER_MAX):
        print("缓存区 %s 还有 %s 条数据" % (i, queue_list[i].qsize()))
        while not queue_list[i].empty():
            print(queue_list[i].get())

4、程序运行结果示例

生产者0 在缓存区2 生产数据 4636
生产者0 在缓存区2 生产数据 1640
生产者0 在缓存区2 生产数据 3452
生产者0 在缓存区2 生产数据 898
消费者0 在缓存区2 消费数据 4636
生产者0 在缓存区2 生产数据 663
消费者0 在缓存区2 消费数据 1640
消费者0 在缓存区2 消费数据 3452
消费者0 在缓存区2 消费数据 898
消费者0 在缓存区2 消费数据 663
生产者1 在缓存区1 生产数据 3609
生产者1 在缓存区1 生产数据 1447
消费者1 在缓存区1 消费数据 3609
消费者1 在缓存区1 消费数据 1447
生产者2 在缓存区2 生产数据 1698
生产者2 在缓存区2 生产数据 2335
生产者2 在缓存区2 生产数据 3085
生产者2 在缓存区2 生产数据 1661
生产者2 在缓存区2 生产数据 507
消费者2 在缓存区2 消费数据 1698
消费者2 在缓存区2 消费数据 2335
消费者2 在缓存区2 消费数据 3085
消费者2 在缓存区2 消费数据 1661
消费者2 在缓存区2 消费数据 507
生产者1 在缓存区1 生产数据 4820
生产者1 在缓存区1 生产数据 834
生产者1 在缓存区1 生产数据 3730

缓存区 0 还有 0 条数据
缓存区 1 还有 3 条数据
4820
834
3730
缓存区 2 还有 0 条数据
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章