前言
上篇文章介紹了 Python 中的多執行緒。今天來介紹下程式設計中常會用到的一個數據結構 - 佇列。
不知道大家是否還記得什麼是資料結構呢?在很早很早以前,Python小課堂的初期,講了許多 Python 原生的資料結構。比如 list、tuple、dict 等。。。
既然叫資料結構,實際上就是為了給計算機儲存資料用的一種結構體。不同的資料結構都有其不同的特點。那今天就來簡單地聊聊佇列!
佇列的概念拋開計算機知識體系,在咱們的生活中,佇列這個詞其實挺好想象的,因為無時無刻都可以見到。比如等公交的時候,需要排隊。比如買東西交錢的時候,也要排隊。在這些例子中,由人們有序形成的隊形就叫佇列。
生活中的排隊,有沒有什麼特性而言呢?大家可以思考下,再往下看。
普通佇列的特性,即先進先出(FIFO,first in first out)。對應到生活中,怎麼理解這個先進先出?其實很好理解。
拿排隊買東西來說,每次排在隊首的人,交完錢肯定是當前佇列中第一個離開收銀臺的人。當隊首的人離開了,那麼後面的所有人都要往前走,繼續結賬。
對應到計算機中的佇列,就是因為第一個人先排的隊,所以他第一個交完錢就可以離開了,即先進先出。(多說句,計算機世界許多東西其實就是抽象的現實世界示例。)
心細的同學會發現,在上面將普通兩字標粗了,那一定還有一些其它的常用特殊佇列,比如優先順序佇列。(PriorityQueue)
這次拿去銀行辦業務來舉例。生活中我們去銀行辦理業務,一般都需要去機器拿號,然後等待著櫃檯業務人員叫號。叫到你,你就過去處理就行了。但是銀行是有 vip 服務的,擁有 vip 權益的人可以更快的享受到業務辦理,也就是說人家比你有更高的優先權。vip特權通道,你值得擁有!
了解了生活中的例子,再來看看比較專業的定義:
優先順序佇列(priority queue) 是0個或多個元素的集合,每個元素都有一個優先權,對優先順序佇列執行的操作有(1)查詢(2)插入一個新元素 (3)刪除 一般情況下,查詢操作用來搜尋優先權最大的元素,刪除操作用來刪除該元素 。對於優先權相同的元素,可按先進先出次序處理或按任意優先權進行。
百度百科
也就是說,在優先順序佇列中,每個人都有一個優先權對應,誰的優先權高,誰就會先被處理。大家了解即可。
示例演示示例情景:
假設下面有 6 個美少女,她們準備去量身高,恰好這幾個妹紙是按照從高到低,從大到小排好隊的。
每走一個去量身高,這個佇列中就會少一個人。當然,隊首在左,隊尾在右,於是她們的變化是下面這樣:
。。。。。。省略,直到:
程式碼演示
是不是好多人看到這裡就不打算看了。。不是讓你來看美少女的喂。。。下面才是重點~
第一部分程式碼:
import queueimport threadingnum_worker_threads = 5def do_work(beauty_dict): print(f"妹紙名字{beauty_dict['name']},年齡{beauty_dict['age']}")def worker(): while True: item = q.get() if item is None: break do_work(item) q.task_done()
簡單的講解下,在 Python3 中,有個模組叫 queue。裡面實現了幾個佇列的資料結構。首先看 do_work() 函式,其中它就是用來列印妹子姓名和年齡的。worker() 函式中寫了一層死迴圈,只要佇列中有妹紙的資料,就一直執行列印,直到佇列中的妹紙都沒了,就跳出。
第二部分程式碼:
q = queue.Queue()threads = []for i in range(num_worker_threads): t = threading.Thread(target=worker) t.start() threads.append(t)beauty_girls = [{"name": "小H", "age": 23}, {"name": "小E", "age": 22}, {"name": "小D", "age": 21}, {"name": "小C", "age": 20}, {"name": "小B", "age": 19}, {"name": "小A", "age": 18}, ]for item in beauty_girls: q.put(item)# block until all tasks are doneq.join()# stop workersfor i in range(num_worker_threads): q.put(None)for t in threads: t.join()
首先建立佇列,其次,讓這 6 個美少女開始依次排入到佇列中,開啟多執行緒去執行 worker() 這個函式。worker() 函式就是第一部分程式碼中,從佇列裡一個個取出妹紙,在呼叫 do_work() 列印她們的姓名和年齡。
關於佇列的 join() 方法,可以看到官方給的英文註釋,大意是當所有任務完成時才繼續執行後面的程式碼,否則處於阻塞狀態。
程式碼中涉及的方法,老規矩,希望大家可以自己去查閱 Python 官方文件,搜尋 queue 即可看到。當然如果懶得動手的話,筆者這裡截圖幾個常用方法:
將妹紙放入佇列中:
從佇列中獲取妹紙:
獲取佇列中妹紙的個數:
總結通過兩篇文章,簡單的介紹了一下多執行緒和佇列,目的是為了接下來的多執行緒佇列爬蟲示例做準備,如果對這些不了解的話,在後面的程式碼中是很難看懂的。
關於佇列的使用,最常用的方法應該就是放入、獲取、判斷佇列的大小。其實這三點在大部分資料結構裡都是常用的操作,熟練掌握即可。
本章完整程式碼,就是文中第一部分和第二部分的程式碼拼接,因為太長,所以分開講了下。
-
1 #
-
2 #
這個除了身高,還有歐派排序
-
3 #
佇列和堆疊,先進先出,先進後出?
-
4 #
Python什麼的……只能看懂英文單詞翻譯……各種符號啊,關係詞啊都不知道怎麼排列。
-
5 #
圖片是輕音少女裡的人物(^-^),大愛輕音
-
6 #
說句實話吧,我是進來看圖的
-
7 #
這個佇列的比喻,讓吾甚是歡喜
-
8 #
不是因為圖片,我才不會點進來。
-
9 #
看到輕音進來,莫名其妙的出去
-
10 #
果然程式設計師都是宅男
-
11 #
只要圖片選的好,瀏覽自然不會少
-
12 #
是不是好多人看到這裡就不打算看了。。不是讓你來看美少女的喂。。。下面才是重點~ 我就是看到這裡不繼續看了
我……我…是衝著圖片進來的…不好意思,打擾了