Python queue (隊列)


queue (隊列)

主要作用

  1. 解耦,使程序實現松耦合(一個模塊修改不會影響其他模塊)
  2. 提高效率

隊列與列表的關系

隊列中數據只有一份,取出就沒有了,區別於列表,列表數據取出只是復制了一份

分類

FIFO (先入先出)

queue.Queue(maxsize=0)
示例:

import queue

q = queue.Queue()
q.put(1)
q.put(2)
q.put(3)

print(q.get())
print(q.get())
print(q.get())

輸出結果:
1
2
3

LIFO (后入先出)

queue.LifoQueue
示例:

import queue

q = queue.LifoQueue()
q.put(1)
q.put(2)
q.put(3)

print(q.get())
print(q.get())
print(q.get())

輸出結果:
3
2
1

PriorityQueue (數據可設置優先級)

queue.PriorityQueue
同優先級的按照 ASCII 排序
示例:

import queue

q = queue.PriorityQueue()
q.put((2, '2'))
q.put((1, '1'))
q.put((3, '3'))
q.put((1, 'a'))

print(q.get())
print(q.get())
print(q.get())
print(q.get())

輸出結果:
(1, '1')
(1, 'a')
(2, '2')
(3, '3')

queue 模塊

queue 模塊中有 Queue 類,LifoQueue、PriorityQueue 都繼承了 Queue

maxsize

maxsize 是實例化 Queue 類時的一個參數,默認為 0
Queue(maxsize=0) 可以控制隊列中數據的容量

put

Queue.put(block=True, timeout=None)
block 用於設置是否阻塞, timeout 用於設置阻塞時等待時長
put_nowait() = put(block=False)

阻塞

當隊列滿了之后,put 就會阻塞,一直等待隊列不再滿時向里面添加數據

不阻塞

當隊列滿了之后,如果設置 put 不阻塞,或者等待時長到了之后會報錯:queue.Full

get

Queue.get(block=True, timeout=None)
get_nowait() = get(block=False)

阻塞

當隊列空了之后,get 就會阻塞,一直等待隊列中有數據后再獲取數據

不阻塞

當隊列空了之后,如果設置 get 不阻塞,或者等待時長到了之后會報錯:_queue.Empty

full & empty

Queue.empty()/Queue.full() 用於判斷隊列是否為空、滿
盡量使用 qsize 代替

qsize

Queue.qsize() 用於獲取隊列中大致的數據量
注意:在多線程的情況下不可靠
因為在獲取 qsize 時,其他線程可能又對隊列進行操作了

join

join 會在隊列存在未完成任務時阻塞,等待隊列無未完成任務,需要配合 task_done 使用

task_done

執行一次 put 會讓未完成任務 +1 ,但是執行 get 並不會讓未完成任務 -1 ,需要使用 task_done 讓未完成任務 -1 ,否則 join 就無法判斷
隊列為空時執行會報錯:ValueError: task_done() called too many times
示例:

import queue
import threading
import time


def q_put():
    for i in range(10):
        q.put('1')
    while True:
        q.put('2')
        time.sleep(1)


def q_get():
    while True:
        temp = q.get()
        q.task_done()
        print(temp)
        time.sleep(0.3)


q = queue.Queue()
t1 = threading.Thread(target=q_put)
t2 = threading.Thread(target=q_get)
t1.start()
t2.start()
q.join()
print('queue is empty now')

主線程執行到 q.join 就開始阻塞,當 t2 線程將隊列中的數據全部取出之后,主線程才繼續執行。
如果將 task_done 注釋掉主線程就永遠阻塞在 q.join,不再繼續向下執行

生產者消費者模型(主要用於解耦)

在多線程開發當中,如果生產線程處理速度很快,而消費線程處理速度很慢,那么生產線程就必須等待消費線程處理完,才能繼續生產數據。同樣的道理,如果消費線程的處理能力大於生產線程,那么消費線程就必須等待生產線程。為了解決這個問題於是引入了生產者和消費者模式
生產者消費者模式是通過一個容器來解決生產者和消費者的強耦合問題。生產者和消費者彼此之間不直接通訊,而通過阻塞隊列來進行通訊,所以生產者生產完數據之后不用等待消費者處理,直接扔給阻塞隊列,消費者不找生產者要數據,而是直接從阻塞隊列里取,阻塞隊列就相當於一個緩沖區,平衡了生產者和消費者的處理能力。
示例:

import threading
import time
import queue


def producer():
    count = 1
    while 1:
        q.put('No.%i' % count)
        print('Producer put No.%i' % count)
        time.sleep(1)
        count += 1


def customer(name):
    while 1:
        print('%s get %s' % (name, q.get()))
        time.sleep(1.5)


q = queue.Queue(maxsize=5)
p = threading.Thread(target=producer, )
c = threading.Thread(target=customer, args=('jack', ))
p.start()
c.start()

使用生成器也可以實現簡單的生產者消費者模型
點擊查看 -> 生成器


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM