孤荷凌寒自學python第四十三天python 的執行緒同步之Queue物件
(完整學習過程螢幕記錄視訊地址在文末,手寫筆記在文末)
Queue物件是直接操作佇列池的物件,佇列中可以存放多種物件,當然也就可以存放執行緒物件,將多個執行緒物件存放於佇列池中之後,就能非常顯式的操作各個執行緒,非常方便。這是今天學習Queue的皮毛之後的感受,第一次感覺對執行緒有了非常完全的掌控,不像最初學習Lock與RLock那樣,那時感覺完全沒有掌控住執行緒。
一、 引用queue模組
Queue來自於模組queue
注意queue模組的首字母是小寫的;而類名稱Queue的名稱首字母是大寫的。
因此使用前必須 宣告引用queue模組:
import queue
二、 得到queue模組中的三個相關佇列類的物件實體(測試程式碼統一在後測試)
在queue模組中其實有三個與佇列相關的類
1
Queue
新的Queue物件=queue. Queue([maxsize])
Queue是指一個 先進先出 的佇列,即先進入佇列 的物件,取出時也先被取出來。
縮寫為:Fifo (First in first out)
2
LifoQueue
新的LifoQueue物件=queue. LifoQueue([maxsize])
LifoQueue是指一個 後進先出 的佇列,即後進入佇列 的物件,取出時卻會被先取出來。
縮寫為:Lifo (Last in first out)
3
PriorityQueue
新的PriorityQueue物件=queue. PriorityQueue ([maxsize])
PriorityQueue是指一個 優先順序 佇列,即不管進入佇列 的順序如何,取出時都按物件標註的 優先順序來安排 取出順序,優先順序數字小的物件會被優先取出來 。
由於初學乍到,沒有深入學習PriorityQueue,發現它的用法較前兩個物件是不同的。
【maxsize】可選形參如果指定 了大於0的實際引數,那麼就表示指定了這個佇列物件的 最大容量(就是說可以容下多少個物件)。如果沒有指定這個形參的實參或指定的實參小於1,那麼都表示這個佇列的容量是無限大的。
三、 Queue物件的主要方法(測試程式碼統一在後測試)
1
Queue物件 . put(物件[,block=True[,timeout=0]])
此方法用於將一個物件放入佇列中,其中可選形參block=True,說明預設值是True,此時表示放入佇列是阻塞式的,阻塞執行緒的時間由timeout決定。
關於阻塞式放入,我目前的理解是,如果 佇列 的最大容量已經滿了,但也要等待佇列中有空位時才將物件放入。這種情況下不會報錯,因為在阻塞下等待佇列中有空位發生,就馬上放進去。不過如果指定有timeout時間,則時間用完就不再阻塞以等待了。
如果 block=False,那麼一旦佇列中沒有空位以將物件放入佇列中,那麼,就直接報錯。
2
Queue物件 . get([,block=True[,timeout=0]])
此方法將取出佇列中當前按優先順序應當被取出來 的下一個物件,將返回一個物件。
其中可選形參block=True,說明預設值是True,此時表示取出佇列中的元素是阻塞式的,阻塞執行緒的時間由timeout決定。
關於阻塞式取出,我目前的理解是,如果 佇列 中已經沒有物件了(佇列為空),但也要等待佇列中有物件時才繼續取出。這種情況下不會報錯,因為在阻塞下等待佇列中有物件發生,就馬上取出來。不過如果 指定有timeout時間,則時間用完就不再阻塞以等待了。
如果 block=False,那麼一旦佇列中已經沒有物件供取出,那麼,就直接報錯。
3
Queue物件 . qsize()
得到佇列中當前的物件個數。
4
Queue物件 . maxsize()
得到佇列中當前定義時設定的最大容量個數。
5
Queue物件 . empty()
此方法將返回佇列是否已經為空,將返回一個布林物件。
6
Queue物件 . not_empty()
此方法將返回佇列是否不是空的,將返回一個布林物件。
7
Queue物件 . full()
此方法將返回佇列是否已經裝滿,將返回一個布林物件。
8
Queue物件 . join()
執行此方法將等待佇列中所有元素都被取出,佇列為空時才執行後續操作。
四、 將檔案由兩個執行緒反覆同步寫和讀的實現由Queue佇列來實現
程式碼如下:
importthreading
import queue
fromdatetime import datetime
from time import sleep
strf='1.txt'
def read(n):
with open(strf,'r',encoding='utf-8') as f:
lstA=f.readlines()
print('讀取第' + str(n) + '次' + str(lstA) + '\n')
def write(n):
with open(strf,'w',encoding='utf-8') as f:
lstA=['寫入','第' + str(n) + '次']
f.writelines(lstA)
#sleep(1)
print(str(lstA) +'\n')
def main():
q=queue.Queue(20)
x=range(10)
for n in x:
tread=threading.Thread(target=read,args=(n,))
twrite=threading.Thread(target=write,args=(n,))
q.put(twrite)
q.put(tread)
x=range(20)
for n in x:
t=q.get()
print('當前佇列中還有物件:' + str(q.qsize())+ '個\n')
t.start()
t.join()
#q.join()
print('主執行緒結束。')
if __name__=='__main__':
main()
執行結果如下:
當前佇列中還有物件:19個
['寫入', '第0次']
當前佇列中還有物件:18個
讀取第0次['寫入第0次']
當前佇列中還有物件:17個
['寫入', '第1次']
當前佇列中還有物件:16個
讀取第1次['寫入第1次']
當前佇列中還有物件:15個
['寫入', '第2次']
當前佇列中還有物件:14個
讀取第2次['寫入第2次']
當前佇列中還有物件:13個
['寫入', '第3次']
當前佇列中還有物件:12個
讀取第3次['寫入第3次']
當前佇列中還有物件:11個
['寫入', '第4次']
當前佇列中還有物件:10個
讀取第4次['寫入第4次']
當前佇列中還有物件:9個
['寫入', '第5次']
當前佇列中還有物件:8個
讀取第5次['寫入第5次']
當前佇列中還有物件:7個
['寫入', '第6次']
當前佇列中還有物件:6個
讀取第6次['寫入第6次']
當前佇列中還有物件:5個
['寫入', '第7次']
當前佇列中還有物件:4個
讀取第7次['寫入第7次']
當前佇列中還有物件:3個
['寫入', '第8次']
當前佇列中還有物件:2個
讀取第8次['寫入第8次']
當前佇列中還有物件:1個
['寫入', '第9次']
當前佇列中還有物件:0個
讀取第9次['寫入第9次']
主執行緒結束。
從結果中看出,讀寫各十次都是成功的,且讀寫交替進行,符合同步要求,且讀寫沒有衝突。
五、 將檔案由兩個執行緒反覆同步寫和讀的實現由LifoQueue佇列來實現
程式碼如下:
importthreading
import queue
fromdatetime import datetime
from time import sleep
strf='1.txt'
def read(n):
with open(strf,'r',encoding='utf-8') as f:
lstA=f.readlines()
print('讀取第' + str(n) + '次' + str(lstA) + '\n')
def write(n):
with open(strf,'w',encoding='utf-8') as f:
lstA=['寫入','第' + str(n) + '次']
f.writelines(lstA)
#sleep(1)
print(str(lstA) +'\n')
def main():
x=range(10)
q=queue.LifoQueue(20)
for n in x :
tread=threading.Thread(target=read,args=(n,))
twrite=threading.Thread(target=write,args=(n,))
q.put(tread)
q.put(twrite)
x=range(q.maxsize)
for n in x:
t=q.get()
t.start()
t.join()
print('主執行緒結束。')
if __name__=='__main__':
main()
執行結果:
['寫入', '第9次']
讀取第9次['寫入第9次']
['寫入', '第8次']
讀取第8次['寫入第8次']
['寫入', '第7次']
讀取第7次['寫入第7次']
['寫入', '第6次']
讀取第6次['寫入第6次']
['寫入', '第5次']
讀取第5次['寫入第5次']
['寫入', '第4次']
讀取第4次['寫入第4次']
['寫入', '第3次']
讀取第3次['寫入第3次']
['寫入', '第2次']
讀取第2次['寫入第2次']
['寫入', '第1次']
讀取第1次['寫入第1次']
['寫入', '第0次']
讀取第0次['寫入第0次']
主執行緒結束。
——————————
今天整理的學習筆記完成,最後例行說明下我的自學思路:
根據過去多年我自學各種程式語言的經歷,認為只有真正體驗式,解決實際問題式的學習才會有真正的效果,即讓學習實際發生。在2004年的時候我開始在一個鄉村小學自學電腦 並學習vb6程式語言,沒有學習同伴,也沒有高師在上,甚至電腦都是孤島(鄉村那時還沒有網路),有的只是一本舊書,在痛苦的自學摸索中,我找到適應自己零基礎的學習方法:首先是每讀書的一小節就作相應的手寫筆記,第二步就是上機測試每一個筆記內容是否實現,其中會發現書中講的其實有出入或錯誤,第三步就是在上機測試之後,將筆記改為電子版,形成最終的修訂好的正確無誤的學習筆記。
通過反覆嘗試錯誤,在那個沒有分享與交流的黑暗時期我摸黑學會了VB6,爾後接觸了其它語言,也曾聽過付費視訊課程,結果發現也許自己學歷果然太低,就算是零基礎的入門課程,其實也難以跟上進度,講師的教學多數出現對初學者的實際情況並不瞭解的情況,況且學習者的個體也存在差異呢?當然更可怕的是收費課程的價格往往是自己難以承受的。
於是我的所有程式設計學習都改為了自學,繼續自己的三步學習筆記法的學習之路。
當然自學的最大問題是會走那麼多的彎路,沒有導師直接輸入式的教學來得直接,好在網路給我們帶來無限搜尋的機會,大家在網路上的學習日誌帶給我們共享交流的機會,而QQ群等交流平臺、網路社群的成立,我們可以一起自學,互相批評交流,也可以獲得更有效,更自主的自學成果。
於是我以人生已過半的年齡,決定繼續我的程式設計自學之路,開始學習python,只希望與大家共同交流,一個人的獨行是可怕的,只有一群人的共同前進才是有希望的。
誠摯期待您的交流分享批評指點!歡迎聯絡我加入從零開始的自學聯盟。
這個時代網際網路成為了一種基礎設施的存在,於是本來在孤獨學習之路上的我們變得不再孤獨,因為網路就是一個新的客廳,我們時刻都可以進行沙龍活動。
非常樂意能與大家一起交流自己自學心得和發現,更希望大家能夠對我學習過程中的錯誤給予指點——是的,這樣我就能有許多免費的高師了——這也是分享時代,社群時代帶來的好福利,我相信大家會的,是吧!
根據完全共享的精神,開源互助的理念,我的個人自學錄製過程是全部按4K高清視訊錄製的,從手寫筆記到驗證手寫筆記的上機操作過程全程錄製,但因為4K高清檔案太大均超過5G以上,所以無法上傳至網路,如有需要可聯絡我QQ578652607對傳,樂意分享。上傳分享到百度網盤的只是壓縮後的720P的視訊。
我的學習過程錄影百度盤地址分享如下:(清晰度:1280x720)
連結:https://pan.baidu.com/s/19BbmLmhXRgtdSXWMWtmabw
提取碼:dy3p
Bilibili:
https://www.bilibili.com/video/av38090801/