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 條數據
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章