動畫:隊列是如何處理大量任務分發的?

在這裏插入圖片描述

像線程池、異步隊列、消息隊列等有限的資源容器中,往往存儲大量的任務事件,這些大量的任務事件需要進行有條理的進行任務分發以及各種情況處理,爲了能夠使得資源容器的正常運行,不得不使用一定的容器結構設計和策略,那麼這些結構和策略如何實現的呢?

那小鹿不買官司了,就是用我們今天即將學到的數據結構“隊列”。雖然我們初學者實際中接觸的少,但是它的實際用途廣着呢,學好這部分是非常關鍵的。


思維導圖

在這裏插入圖片描述

1、什麼是隊列?

何爲隊列?顧名思義,排隊就是一個很好的例子。如果我們餐廳刷卡買飯,學生依次排隊,已購買完飯的在隊頭走了,剛來的同學就要排在隊尾後邊排隊。而不能直接在排好隊中插隊,這樣也壞了排隊這種“先來先去”規矩。
在這裏插入圖片描述

2、隊列的特點?

棧有出棧和入棧兩種,隊列也有入隊和出隊兩種操作,只不過是棧是先來後走,隊列則相反,先來先走。
在這裏插入圖片描述
正是因爲隊列這種特點,使得它在一些有限的資源容器中的到廣泛的應用,比如線程池、資源池、消息隊列等。


3、如何實現隊列?

隊列和棧一樣,也有兩種實現方式,一種是順序隊列,一種是鏈式隊列。但是我們之前的文章中說過,無論是順序還是鏈式,都是由數組和鏈表演化而來,只不過是操作上進行了改進。


3.1 順序隊列

在這裏插入圖片描述
對於上邊的數組順序隊列,不知道大家有沒有發現一個問題就是,如果我一直的出隊、入隊會出現下邊這樣一種情況。
在這裏插入圖片描述
此時隊列再入隊,但是隊尾已滿,但是我們看到的明明隊頭還有空間的,如果此時擴大容量不就相當於浪費空間嗎?

那還有一個方法就是,每入隊一個元素,整體數據就往前移動一個空間,你可能會說,這樣操作起來是不是很費勁,而且效率不高,是的,這樣的確效率不高。

如果我們稍微改進一下,如果隊尾有空間,我們就讓元素一直入隊,直到隊尾沒有空間位置,然後進行整體進行一次搬移,這樣優化了入隊的效率。將這一次性進行大量搬移數據平均到每次上,平均時間複雜度還是 O(1)。
在這裏插入圖片描述


3.2 鏈式隊列

鏈式隊列是以鏈表組成的,它的優點就是可以無限的進行入隊,不用動態擴容。
在這裏插入圖片描述

4、隊列的種類?

4.1 循環隊列

循環隊列,顧名思義,將一般的隊列進行頭尾相接,形成一個圓,聲明兩個指針,一個帶邊隊頭,一個代表隊尾,入隊和出隊的時候,直接操作對應的指針即可。

但是爲什麼會出現循環隊列呢?是否還記得我們上邊所述,普通的隊列需要進行大量數據搬移,而循環隊列則沒有這個缺點。

但是循環隊列有一個比較重要的點就是判空和判斷是否已滿。
在這裏插入圖片描述
如上圖所示,判空的條件很簡單,頭指針等於尾指針的時候,此時循環隊列爲空。

在這裏插入圖片描述
循環隊列滿的時候,我們要發現其上邊的規律得出隊滿的條件,(尾指針 + 1)% n = 頭指針。此時的循環隊列會浪費一個空間。
在這裏插入圖片描述
上邊我們涉及到的隊列是從結構上進行來區分的,下面我們就從實際開發功能上進行劃分。其實就是對一些功能的需求對隊列操作上設定了一定的要求。


4.2 阻塞隊列

我們拿一個例子入手,如果你學習過Android開發,裏邊有個MessageQueue消息隊列。如果沒有接觸過,也沒關係,可以將其理解爲放置消息的一個容器。

這個容器主要存放系統給它分發的任務消息,然後當有線程來分配任務的時候,此時該容器,也就是消息隊列就會在隊列中拿出任務然後分發給線程去執行。但是有這樣兩種情況需要進行設計。

第一種情況就是當任務消息隊列沒有任務的時候,此時線程來拿任務,該怎麼辦?

在這裏插入圖片描述
第二種情況就是,當沒有空閒線程來取任務,此時任務消息隊列已經滿了,系統再分發新的任務時,又該如何處理呢?
在這裏插入圖片描述

那我相對於這兩種情況,就用到我們的阻塞隊列。當遇到第一種情況時,此時消息隊列爲空,在隊頭拿數據的時候會被阻塞,也就是被阻止了,因爲隊列中爲空,只有等到隊列中有新的數據時,線程纔可以拿去新的任務。

當遇到第二種情況,如果隊列已經滿了,此時沒有空餘線程來取任務,此時隊列也被阻塞了,當有空餘線程來獲取任務的時候,任務隊列纔可取數據。

其實上邊的設計思路和我們所涉及到的設計模式中的 “發佈-訂閱者模式”相同。

生產者代表往消息隊列中增加數據,消費者代表線程不斷的拿去任務去執行,我們可以通過調節生產着和消費者的數量來調節隊列彙總的任務數量,從而達到高效的系統運行。


4.3 併發隊列

上邊我們涉及到的阻塞隊列會有很多的消費者(線程)去操作隊列。我們舉個具體點的例子,還是拿排隊打飯的例子,如果一個窗口沒有排序秩序,100 多個人都往窗口買飯,如果你作爲賣飯的,想象一下會出現什麼情況呢?
在這裏插入圖片描述
學生爭來爭去到底先給哪一個盛飯呢?一旦人一多,可能整個餐廳窗口擠爆,會出現打架的情況。

話說回來,在系統中也可能出現這種情況的,那我們怎麼對付這種情況呢?此時的隊列不再叫做阻塞隊列,叫做併發隊列。
在這裏插入圖片描述
我們只需要設置一個鎖機制,當有一個消費者來取任務的時候,我們此時加一個鎖,說明其他的消費者不能進行操作了,當這個消費者讀取完任務時,在解鎖,依次類推,這樣保證了系統的正常運行。


小結

最後我們來總結一下隊列的應用,像我們開篇所說,隊列一般應用在有限的資源場景中,比如消息隊列、異步隊列、CPU 的線程執行隊列等。對於這些應用場景,都是利用了隊列先來先去的服務調度方式,從而能夠準確的對資源進行把控。

隊列在實際應用中也分爲兩種,一種是基於數組的順序隊列,另一種是基於鏈表的鏈式隊列。它們兩者各有優缺點,所謂的優缺點也是由數組和兩邊本身的優缺點演化而來。

數組大小固定,如果有過多的請求,就會導致長時間排隊等候,請求響應時間過長。而鏈式隊列雖然可以動態的添加任務,但是如果過於太長,在實際應用中也是不允許的。

對於如何在實際應用中設計一個合適的隊列,需要根於已有的資源容量以及需求,還有系統的響應時間要求進行設計。如果隊列太長,會導致等待請求過多,隊列太小,就無法充分利用系統的資源。



❤️ 不要忘記留下你學習的腳印 [點贊 + 收藏 + 評論]

文章都看完了,爲何不妨點個贊呢?嘻嘻,那就說明你很自私,你怕那麼好的文章讓別人也看到。開個小小玩笑。



❤️ 本文首發於原創公衆號:「小鹿動畫學編程」更多優質文章請關注小鹿的公衆號幺。

一個致力於初學者動畫學習編程的公衆號,後臺回覆“資料”,即可獲取小鹿自學以來整理資料一份。

在這裏插入圖片描述


作者Info:

【作者】:小鹿

【原創公衆號】:小鹿動畫學編程。

【簡介】:和小鹿同學一起用動畫的方式從零基礎學編程,將 Web前端領域、數據結構與算法、網絡原理等通俗易懂的呈獻給小夥伴。先定個小目標,原創 1000 篇的動畫技術文章,和各位小夥伴共同努力一起學習!公衆號回覆 “資料” 送一從零自學資料大禮包!

【轉載說明】:轉載請說明出處,謝謝合作!~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章