二十三、Python隊列實現多執行緒(下篇)

@Author: Runsen

在Python中,主要採用隊列和執行緒的方法來實現多執行緒。

@[TOC]

隊列

隊列(queue),是先進先出(FIFO, First-In-First-Out)的線性表,在具體應用中通常用鏈表或者數組來實現,隊列只允許在後端(稱為rear)進行插入操作,在前端(稱為front)進行刪除操作,隊列的操作方式和堆棧類似,唯一的區別在於隊列只允許新數據在後端進行添加。

在Python中隊列可以通過內置模組queue導入,具體導入方法:from queue import Queue。

queue

queue模組提供了適合多執行緒編程的先進先出的數據結構,可以用來在生產者和消費者執行緒之間安全的傳遞消息或者數據;鎖是調用方處理,因此多執行緒可以安全、方便的使用同一隊列實現。

常用屬性和方法:

介面描述
put(x)入隊
get()出隊
empty()判斷隊列是否為空
full()判斷隊列是否未滿
qsize()隊列的當前長度
task_done()任務結束
join()等待完成

Queue類實現了一個基本的先進先出容器。使用put方法將元素增加到序列的一端,使用get方法從另一端刪除,具體程式碼如下。

import queue

q = queue.Queue()

#添加元素
for i in range(5):
    q.put(i)

#刪除元素
while not q.empty():
    print(q.get())

運行上面的程式,你將會看到下面的輸出:

0
1
2
3
4

生產者/消費者模式

我們經常會遇到這樣的一個問題,這裡有成千上萬條數據,每次需要取出其中的一條數據進行處理,那麼引入多執行緒該怎麼進行任務分配?

我們可以將數據進行分割然後交給多個執行緒去跑,因為執行緒間數據的共享的問題。

它包含兩類進程:一種只是用來生產數據,例外一種只是用來消費數據.為了串聯他們,通常會採用共享的數據區域,就像一個倉庫.生產者產生的數據都放入倉庫中並不需要關注消費者的行為,消費者只需要從共享倉庫中獲取數據,並不需要關心生產者的行為.

# -*- coding:utf-8 -*-
# time :2019/4/23 10:13
# Author: Maoli

import threading
import time
import random
MONEY = 0
gLock = threading.Lock()

def Procuder():
    while True:
        global MONEY
        random_money = random.randint(10,100)
        gLock.acquire() #加鎖
        MONEY += random_money
        gLock.release() #釋放鎖
        print ('生產者%s-生產了%d' % (threading.current_thread,random_money))
        time.sleep(0.5)

def Customer():
    while True:
        global MONEY
        random_money = random.randint(10,100)
        if MONEY > random_money:
            print ('消費者%s-消費了:%d' % (threading.current_thread,random_money))
            gLock.acquire()
            MONEY -= random_money
            gLock.release()
        else:
            print ('需要消費的錢為:%d,餘額為:%d,' % (random_money,MONEY))
        time.sleep(0.5)

def p_c_test():
    # 執行3個執行緒,來當作生產者
    for x in range(3):
        th = threading.Thread(target=Procuder)
        th.start()
    # 執行3個執行緒,來當作消費者
    for x in range(3):
        th = threading.Thread(target=Customer)
        th.start()

if __name__ == "__main__":
    p_c_test()

運行截圖如下:

隊列實現多執行緒

在這裡我們可以使用隊列與執行緒相結合的方式進行任務分配。在生產消費者模式當中用到的是阻塞型queue。在Python當中,我們最常用的queue就是一個支援多執行緒場景的阻塞隊列

隊列執行緒的思想: 首先創建一個全局共享的隊列,隊列中只存在有限個元素,並將所有的數據逐條加入到隊列中,並調用隊列的join函數進行等待。之後便可以開啟若干執行緒,執行緒的任務就是不斷的從隊列中取數據進行處理就可以了。

# -*- coding:utf-8 -*-
# time :2019/4/23 10:35
# Author: Maoli

import threading
import time
import queue

# 下面來通過多執行緒來處理Queue裡面的任務:
def work(q):
    while True:
        if q.empty():
            return
        else:
            t = q.get()
            print("當前執行緒sleep {} 秒".format(t))
            time.sleep(t)

def main():
    q = queue.Queue()
    for i in range(5):
        q.put(i)  # 往隊列里生成消息
    thread_num = 5
    threads = []
    for i in range(thread_num):
        t = threading.Thread(target=work, args=(q,))
        # args需要輸出的是一個元組,如果只有一個參數,後面加,表示元組,否則會報錯
        threads.append(t)
    # 創建5個執行緒
    for i in range(thread_num):
        threads[i].start()
    for i in range(thread_num):
        threads[i].join()

if __name__ == "__main__":
    start = time.time()
    main()
    print('耗時:', time.time() - start)

運行上面的程式,你將會看到下面的輸出:

當前執行緒sleep 0 秒
當前執行緒sleep 1 秒
當前執行緒sleep 2 秒
當前執行緒sleep 3 秒
當前執行緒sleep 4 秒
耗時: 4.002955436706543

今天也學到了很多東西呢,明天有什麼新知識呢?真期待鴨如果喜歡文章可以關注我哦

本文已收錄 GitHub,傳送門~ ,裡面更有大廠面試完整考點,歡迎 Star。



Tags: