首頁>技術>

前言

上篇文章介紹了 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 #

    是不是好多人看到這裡就不打算看了。。不是讓你來看美少女的喂。。。下面才是重點~ 我就是看到這裡不繼續看了

  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • Node.JS實戰31:大名鼎鼎的Express