Linux CPU調度策略

在談調度策略前,我們先做一些假設。

  1. 每個任務都運行相同的時間

  2. 所有任務到達的時間都是一樣的

  3. 一旦運行了,任務就會運行到完成。

  4. 所有的任務只佔用cpu資源

  5. 任務的運行時間是已知的

    這裏的大部分假設都是不切合實際的,但是這個假設幫助我們更好的去理解和描述調度器。

    我們定義週轉時間爲完成時間減去任務到達時間。

    Tturnaround = Tcompletion - Tarrival

FIFO

最基本的調度算法就是先進先出FIFO模式,有時也被縮寫成FCFS(先到先服務)。FIFO有一些優點:

非常簡單所以容易實現。

假設所有的任務 A,B,C都大概同時到達系統,(Tarrival = 0),具體時間A早於B,B早於C。假設每個任務都工作10秒,那麼平均週轉時間爲(10+20+30)/3 = 20秒。

接下來我們去掉假設1,A運行100秒,B和C都是10秒。那麼平均週轉時間爲(100+110+120)/3 = 110秒,週轉時間比較高了。這個問題在於低消耗的任務排隊到了高消耗的任務後面導致的。這個就導致我們想到了應該把低消耗的任務排在前面去。就是下面談的SJF

SJF

上述的場景中,使用Shortest Job First (SJF)算法,那麼B--C--A的順序排序那麼平均週轉時間爲(10+20+120)/3 =50。

基於假設,所有的任務都是同時到達的基礎上,SJF的調度方法確實是個更好的優化算法。

接下來我們在放鬆假設2,任務可能在任何時候到達。假設A在t=0時到達並運行100秒,B和C分別在t=10時到達,並運行10秒。即使B和C任務更短,B和C還是必須等待A完成後才能執行。平均週轉週期爲(100+110-10 + 120-10) / 3 = 103.33秒。

STCF

我們在來放鬆假設3,調度器需要一些機制,時鐘中斷以及上下文切換。當B和C到達後,調度器會做些事情,會搶佔A,然後決定運行一個其他任務然後在運行A。

 

把搶佔模式加入SJF中後,產生了STCF算法。當有新任務到達系統後,STCF調度器會根據的剩下的所有任務哪個剩餘時間最短就調度哪個。在我們的例子中會搶佔A,運行B和C。平均週轉週期爲((120-0)+(20-10)+(30-10))/3 = 50秒。STCF是基於放鬆假設3的一個最好的優化。

一個新的衡量標準:響應時間

如果我們知道任務長度以及只是使用cpu這些假設,那麼衡量標準就是週轉時間,STCF就是個很好的策略。早期的批處理操作系統中,這類調度算法還是有意義。然而分時操作系統引入後,一切都改變了。因爲需要交互,所以現在引入了一個新的衡量標準:響應時間。

定義響應時間爲從任務第一次到達系統到第一次被調度的時間差。

Tresponse = Tfirstrun - Tarrival

這種度量標準STCF也會有較差的響應時間。如果三個任務同時到達,最後一個任務需要等待前兩個任務完全完成後纔可以被調度到一次。然而很好的週轉時間並不能帶來很好的響應時間。

Round Robin

爲了解決上述的問題,我們引入一個新的調度算法,傳統上被稱爲Round Robin調度模式。RR運行一個任務一個時間片的時間,然後接着切換到隊列中的下一個任務。調度器會重複這個過程,直到所有任務都完成。時間片的時間一定要是要是時鐘中斷的整數倍,如果每隔10ms時鐘中斷,那麼時間片會是10,20或者其他整數倍於10ms。

時間片切的越小,響應時間就越短。但是如果時間片如果太短的話,上下文的切換的消耗就會影響性能了,因爲不會不停的上下文切換。所以系統設計者會考慮一個折中的值,使得上下文切換的消耗和響應時間都能接受。

上下文切換的成本不僅僅是保存和恢復一些寄存器。當程序一直運行會有良好的狀態,cpu cache,TLSB,分支預測以及其他硬件。當切換到其他程序後,這些狀態都會被刷新掉,這會導致一些顯而易見的性能消耗。

假設A,B,C同時到達,分別都運行5秒,時間片爲1秒。在回到之前談到的平均週轉時間,在RR調度策略中,週轉時間分別是13,14,以及15秒。平均週轉爲14秒。確實很糟糕。

如果衡量標準是週轉時間,RR策略確實是個很差的方法。RR會延長把任務儘可能的延長,通過運行每個任務一小段時間然後切換到下一個。在度量週轉時間上,RR甚至比FIFO還更差的一個策略。

RR犧牲週轉時間換取響應時間,如果不想公平的話,那麼就先運行短任務,但是代價就是響應時間。如果想公平的話,響應時間會很少,然後週轉時間就會變大。這就是魚和熊掌不可兼得啊。

我們已經有了低週轉時間的策略(SJF,STCE)以及低響應時間的策略(RR)。我們仍然有2個假設還需要放開。假設4(任務沒使用I/O)以及假設5(每個任務的運行時間是已知的)

合併I/O

我們首先放開假設4。假設一個程序沒有輸入,只產生輸出。

當一個任務產生I/O請求時,調度器顯然會採取一些措施,因爲當前運行的程序在I/O期間不會在使用cpu了,中間會阻塞着等待I/O完成,完成後纔會繼續使用cpu。當I/O被髮送到硬件驅動後,進程阻塞幾毫秒甚至更長,因此調度器當然應該調度其他任務來運行了。

當I/O完成時,調度器同樣會做一些決定。當I/O完成後,中斷產生了,接着操作系統會把產生I/O並且阻塞的進程重新設置成就緒狀態,甚至可以立馬運行他。

爲了更好的理解,我們假設有2個任務A和B,分別需要50ms的cpu時間。然而A運行10ms,然後產生個I/O請求(假設消耗10ms),B只是單純的運行50ms,並沒有任何I/O。調度器先運行A 然後在運行B。

假定我們使用STCF調度器,如果不允許重疊,就如圖7.8所示,非常低的系統利用率。

 

 

一個通常的辦法是把A的每個10ms運行的一個子任務當場一個獨立的任務,使用STCF時,選擇很明確的,每次選擇A的子任務(10ms的子任務),在I/O等待期間在會運行B。通過允許重疊,這樣會大大提高系統利用率。

此時,我們看到了調度器如何合併I/O。把任務劃分成子任務時,cpu會更好保障交互式程序更頻繁的運行着。當交互程序執行I/O時,cpu密集型的程序可以運行了,這樣會提高系統利用率。

 

Multi-level Feed- back Queue (MLFQ) 圖靈獎

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