1.Queue的用法
通常配合threading使用,創建一個隊列,多個線程可以從隊列中提取任務,返回輸入任務
那麼具體是怎麼配送threading模塊使用的呢?
舉個例子,比如你要下載一個文件,可是你發現對方給你限制了你的下載速度,每個文件只准10kb的下載,這時候你可以將下載文件所有的請求丟到一個隊列裏面 Queue.put()
(假設1000個請求),這個隊列就是Queue,然後你設置100個線程,每個線程都可以直接通過Queue.get()
來拿到屬於自己的任務,最後使用Queue.task_done()
告訴隊列,這個任務我完成了。這樣你就相當於擁有了下載100個文件的速度來下載這一個文件。
from queue import Queue
q = Queue()#可以設置maxsize設置最多隊列長度
方法 | 作用 |
---|---|
Queue.qsize() | 返回隊列的大小 |
Queue.empty() | 如果隊列爲空,返回True,反之False |
Queue.full() | 與empty相反,返回True,反之False |
Queue.get() | 獲取隊列 ,get put都有timeout參數,表示等待時間 |
Queue.get_nowait() | 非阻塞獲取隊列 |
Queue.put() | 寫入隊列 |
Queue.put_nowait() | 非阻塞寫入隊列 |
Queue.task_done() | 告訴隊列該任務已經處理完畢 |
Queue.join() | 等到隊列爲空,再執行別的操作 |
具體使用
先看看這個代碼
from queue import Queue
import threading
import time
start_time = time.time()
q = Queue()
for i in range(1,11): #爲q隊列添加10個數字
q.put(i)
def f1(): #假設是一個需要1s時間才能完成的程序
while True: #循環,使線程一直從q中獲取數據
num = q.get()
print("現在處理隊列中的", num)
time.sleep(1)
print("隊列{}完成".format(str(num)))
q.task_done()
def f2(): #計時器
for i in range(10):
time.sleep(1)
print("程序已運行{}s".format(str(int(time.time()-start_time))))
thread_list = []
t1 = threading.Thread(target=f1)
thread_list.append(t1)
t2 = threading.Thread(target=f2)
thread_list.append(t2)
for t in thread_list:
t.setDaemon(True) #子線程會在不重要的主線程結束,子線程結束
t.start()
q.join() #讓主線程阻塞,等待隊列任務全部完成,防止主線程結束導致子線程也被殺死
print("主線程結束")
結果
現在處理隊列中的 1
隊列1完成
現在處理隊列中的 2
程序已運行1s
隊列2完成
現在處理隊列中的 3
程序已運行2s
隊列3完成
現在處理隊列中的 4
程序已運行3s
隊列4完成
現在處理隊列中的 5
程序已運行4s
隊列5完成
現在處理隊列中的 6
程序已運行5s
隊列6完成
現在處理隊列中的 7
程序已運行6s
程序已運行7s
隊列7完成
現在處理隊列中的 8
隊列8完成
程序已運行8s
現在處理隊列中的 9
程序已運行9s
隊列9完成
現在處理隊列中的 10
隊列10完成
程序已運行10s
主線程結束
進程完成,退出碼 0
可能有人就要說,你這用不用Queue結果不都一樣嗎,還不是10s完成
說了要用多線程的,不要急,這個只是個對照代碼,只需要修改一點點,就可以完成多線程
3個線程去完成任務
from queue import Queue
import threading
import time
start_time = time.time()
q = Queue()
for i in range(1,11): #爲q隊列添加10個數字
q.put(i)
def f1(): #假設是一個需要1s時間才能完成的程序
while True:
num = q.get()
print("現在處理隊列中的", num)
time.sleep(1)
print("隊列{}完成".format(str(num)))
q.task_done()
def f2(): #計時器
for i in range(10):
time.sleep(1)
print("程序已運行{}s".format(str(int(time.time()-start_time))))
thread_list = []
for i in range(3): #3個線程
t1 = threading.Thread(target=f1)
thread_list.append(t1)
t2 = threading.Thread(target=f2)
thread_list.append(t2)
for t in thread_list:
t.setDaemon(True) #子線程會在不重要的主線程結束,子線程結束
t.start()
q.join() #讓主線程阻塞,等待隊列任務全部完成,防止主線程結束導致子線程也被殺死
print("主線程結束")
結果
現在處理隊列中的 1
現在處理隊列中的 2
現在處理隊列中的 3
隊列3完成
程序已運行1s
隊列2完成
現在處理隊列中的 4
隊列1完成
現在處理隊列中的 5
現在處理隊列中的 6
隊列4完成
隊列5完成
程序已運行2s
隊列6完成
現在處理隊列中的 7
現在處理隊列中的 8
現在處理隊列中的 9
程序已運行3s
隊列7完成
現在處理隊列中的 10
隊列9完成
隊列8完成
程序已運行4s
隊列10完成
主線程結束
沒錯只用了4s就完成了10個數據的處理
如果用5個線程,那就是2s
現在處理隊列中的 1
現在處理隊列中的 2
現在處理隊列中的 3
現在處理隊列中的 4
現在處理隊列中的 5
隊列1完成
隊列4完成
現在處理隊列中的 6
隊列3完成
隊列2完成
現在處理隊列中的 7
現在處理隊列中的 8
現在處理隊列中的 9
程序已運行1s
隊列5完成
現在處理隊列中的 10
隊列6完成
隊列7完成
程序已運行2s
隊列8完成
隊列9完成
隊列10完成
主線程結束
那有人就要說,那我直接使用10個線程來處理這10個數據不就行了嗎,幹嘛還用着Queue呢
很簡單的道理,如果這個數據是動態的,可能前一秒給10個後一秒給4個,再加上程序沒辦法及時將數據處理完,那麼這個程序很容易出錯或者卡住。