python多線程編程準備(三)
已經有好長一段時間沒有更新過博客了,完成了網課的一個段落的學習,終於有時間寫博客啦😁之前學習了Python爬蟲的一系列東西,自己現在可以應對基本的抓站,瞭解了不同的基本反爬形式和解決辦法,感興趣的小夥伴可以看看我之前博客喲😘
之前所寫的爬蟲可以理解爲都是單線程爬蟲,當抓取大量的數據的時候速度會慢,通過一下的代碼可以知道我們的代碼都是在MainThread下運行的,也就是Python的主線程。之前我寫過關於Python多線程的簡單使用以及簡單的線程併發和鎖機制,感興趣的小夥伴可以看一下,足以應對簡單的多線程爬蟲的使用。
Python—多線程編程(一)線程的創建,管理,停止
Python—多線程編程(二)線程安全(臨界資源問題和多線程同步)
import threading
t = threading.main_thread()
#主線程的名字
print(t.name)
但是這些鎖機制在使用的時候要是原理不清楚,或者是在寫代碼的時候手抖了一下寫錯了位置,就會造成很大的麻煩,今天和大家分享一下Python中Queue(隊列)的使用,隊列是線程之間最常用的通信方法,自帶鎖機制,所以在多線程爬蟲中非常適用。由於自己也是小白,以下的內容也是我瀏覽了許多大佬寫的博文查閱資料後整理想和大家分享的。
先簡單介紹一下隊列
線程優先級隊列( Queue)
Python 的 Queue 模塊中提供了同步的、線程安全的隊列類,包括FIFO(先入先出)隊列Queue,LIFO(後入先出)隊列LifoQueue,和優先級隊列 PriorityQueue。
這些隊列都實現了鎖原語,能夠在多線程中直接使用,可以使用隊列來實現線程間的同步。
Queue的基本方法
Queue 模塊中的常用方法:
Queue.qsize() 返回隊列的大小
Queue.empty() 如果隊列爲空,返回True,反之False
Queue.full() 如果隊列滿了,返回True,反之False
Queue.full 與 maxsize 大小對應
Queue.get([block[, timeout]])獲取隊列,timeout等待時間
Queue.get_nowait() 相當Queue.get(False)
Queue.put(item) 寫入隊列,timeout等待時間
Queue.put_nowait(item) 相當Queue.put(item, False)
Queue.task_done() 在完成一項工作之後,Queue.task_done()函數向任務已經完成的隊列發送一個信號
Queue.join() 實際上意味着等到隊列爲空,再執行別的操作
代碼中解釋常用方法
1.導入模塊
queue屬於Pyhon的內置模塊,不需要 pip install ,直接使用就好,我的編譯器是Pycharm
from queue import Queue
2.基本方法
(1)創建一個隊列對象,先進先出隊列,可選參數maxsize來設定隊列長度。如果maxsize小於1就表示隊列長度無限
q = Queue(maxsize = 10)
print(q)
輸出 <queue.Queue object at 0x000002446D40C400>,是一個Queue的對象
(2)將一個值放入隊列當中
調用隊列對象的get()方法從隊頭刪除並返回一個項目。可選參數爲block,默認爲True。如果隊列爲空且block爲True,get()就使調用線程暫停,直至有項目可用。如果隊列爲空且block爲False,隊列將引發Empty異常。
q.put(10)
print(q.get()) #輸出 10
print(q.get())
print(q.get(block=False))
這裏我嘗試了三種可能,首先放入一個值,再取出;隊列爲空,再嘗試取出,此時 block 的值爲 True;最後將 block 的值設置爲 False 。以下爲後兩種情況的輸出結果:
隊列爲空,再嘗試取出,此時 block 的值爲 True,可以看到代碼在一直執行
將 block 的值設置爲 False:可以看到隊列爲空,直接報錯
解釋:
q.get()
調用隊列對象的get()方法從隊頭刪除並返回一個項目。可選參數爲block,默認爲True。如果隊列爲空且block爲True,get()就使調用線程暫停,直至有項目可用。如果隊列爲空且block爲False,隊列將引發Empty異常。
(3)先進先出隊列(一次性放入多個值)
# 放入多個值,先進先出
# for i in range(1,6):
# q.put(i)
# print('先進先出隊列:{0};是否爲空:{1};隊列大小:{2};是否滿:{3}'.format(q.queue,q.empty(),q.qsize(),q.full()))
# for i in range(5):
# print(q.get())
可以看到是按進來的順序輸出的。
(4)後進先出隊列
#後進先出隊列
lq = LifoQueue(maxsize = 10)
for i in range(1,6):
lq.put(i)
for i in range(5):
print(lq.get())
執行結果:
(5)優先級隊列
#優先級隊列
pq = PriorityQueue(maxsize = 10)
for i in range(1,6):
pq.put(i)
for i in range(5):
print(pq.get())
執行結果:
簡單的實際應用
隊列是線程之間最常用的通信方法,自帶鎖機制,模擬售票
q = Queue(maxsize = 0)
def product(name):
count = 1
while True:
q.put('產生出的第{}票'.format(count))
print('{0}生產出第{1}票'.format(name,count))
count+=1
time.sleep(5)
def consume(name):
while True:
print('{0}賣出了總部{1}'.format(name,q.get()))
time.sleep(1)
q.task_done()
t1 = threading.Thread(target=product,args=('總部',))
t2 = threading.Thread(target=consume,args=('售票廳1',))
t3 = threading.Thread(target=consume,args=('售票廳2',))
t1.start()
t2.start()
t3.start()
接下來可以再對線程池進行學習瞭解,之後就可以開始多線程爬蟲的聯繫啦,當抓取的數據多的時候,可以大大的增加爬取的速度。