1. 程式人生 > 程式設計 >程式排程, 一個排程器的自白

程式排程, 一個排程器的自白

我是一個程式排程器。

我的職責是排程計算機內所有的程式,為他們分配 CPU 資源。

1. 批處理時代

想當初,作業系統創造我時,只是打算讓我用 FCFS 排程演演算法,簡單維護下程式的秩序。但我後來的發展,遠遠超過了他的想象。

1.1 FCFS

所謂 FCFS 就是「先來先服務(First Come First Serve)」,每個程式按進入記憶體的時間先後排成一隊。每當 CPU 上的程式執行完畢或者阻塞,我就會選擇隊伍最前面的程式,帶著他前往 CPU 執行。

就拿這幾個程式來說吧:

按照 FCFS 演演算法,我就會就按 A,B,C,D,E這樣的順序來將他們送往 CPU:

這一演演算法聽起來簡單又公平,然而好景不長,我收到了一個短程式的抱怨:”上次我前面排了一個長程式,等了足足 200 秒他才執行完。我只用 1 秒就執行結束了,就因為等他,我多花了這麼長時間,太不值得了。”

我仔細一想, FCFS 演演算法確實有這個缺陷——短程式的響應時間太長了,使用者互動體驗會變差。

所以我決定,更換排程演演算法。

1.2 SPN

這次我設計的演演算法叫做「短任務優先」(Shortest Process Next,SPN)。每次選擇預計處理時間最短的程式。因此,在排隊的時候,我會把短程式從佇列裡提到前面。

這一次,短程式得到了很好的照顧,程式的平均響應時間大大降低,我和作業系統都很滿意。

但長程式們不幹了:那些短程式天天插隊,導致他們經常得不到 CPU 資源,造成了「飢餓」現象。

取消 SPN 演演算法的呼聲越來越高。

這可是個大問題。FCFS 雖然響應時間長,但最後所有程式一定有使用 CPU 資源的機會。但 SPN 演演算法就不一樣了,如果短程式源源不斷加入佇列,長程式們將永遠得不到執行的機會——太可怕了。

因此,短任務優先演演算法需要得到改進。有什麼方法既能照顧短程式,又能照顧長程式呢?

1.3 HRRN

經過和作業系統的討論,我們決定綜合考量程式的兩個屬性:等待時間要求服務時間——等待時間長,要求服務時間短(就是短程式)的程式更容易被選中。

為了量化,我們制定了一個公式:響應比 = (等待時間+要求服務時間)/ 要求服務時間。響應比高的演演算法會先執行。我們稱之為「高響應比優先」(Highest Response Ratio Next,HRRN)。

這個演演算法得到了長短程式的一致好評。雖然我的工作量增加了(每次排程前,我都要重新計算所有等待程式的響應比)但為了程式們的公平性,這一切都是值得的。

2. 併發時代

新時代到了。

隨著計算機的普及,個人使用者大量增長,併發,即一次執行多個程式的需求出現了。這可難倒我了——處理器只有一個,怎麼執行多個程式?

所幸 CPU 點醒了我:“我現在的運算速度既然這麼快,何不發揮這項長處,弄一個「偽並行」出來?“

“偽並行?什麼意思”

“就是看起來像並行,實際上還是序列。每個程式短時間交替使用我的資源,但在人類看來,這些程式就像在「同時」執行。”

我恍然大悟。

2.1 RR

經過 CPU 的提醒,我很快制定出了新的排程演演算法——時間片輪轉演演算法(Round Robin,RR)。

在這個演演算法裡,每個程式將輪流使用 CPU 資源,只不過在他們開始執行時,我會為他們開啟定時器,如果定時器到時間(或者執行阻塞操作),程式將被迫「下機」,切換至下一個程式。至於下一個程式的選擇嘛,直接用 FCFS 就好了。

新的演演算法必然會面臨新的問題,現在我的問題就是,時間片的長度怎麼設計?

直觀來看,時間片越短,固定時間裡可執行的程式就越多,可 CPU 說過,切換程式是要消耗他不少指令週期的,時間片過短會導致大量 CPU 資源浪費在切換上下文上。時間片過長,短互動指令響應會變慢。所以具體怎麼取,還得看互動時間大小(感覺像沒說一樣,但至少給了個標準嘛)。

這一階段,我的工作量大大提升——以前十幾秒都不用切換一次程式,現在倒好,一秒鐘就得切換數十次。

2.2 VRR

時間片輪轉演演算法看起來十分公平——所有的程式時間片都是一樣的。但事實真是這樣嗎?

I/O 密集型程式不這麼認為,他對我說:“排程器大哥,時間片輪轉沒有照顧到我們這類程式啊!我們經常在 CPU 沒呆到一半時間片,就遇到了阻塞操作,被你趕下去。而且我們在阻塞佇列,往往要停留很長時間。等阻塞操作結束,我們還得在就緒佇列排好長時間隊。那些處理器密集型程式,使用了大部分的處理器時間,導致我們效能降低,響應時間跟不上”

考慮到這些程式的要求,我決定為他們建立一個新的輔助佇列。阻塞解除的程式,將進入這個輔助佇列,進行程式排程時,優先選擇輔助佇列裡的程式。

這就是「虛擬輪轉法」(Virtual Round Robin,VRR)。

從後來實際效能結果來看,這種方法確實優於輪轉法。我頗為自豪。

2.3 優先順序排程

有一天,作業系統忽然找到我,神神祕祕的說:“排程器啊,你是知道的,我要給整個系統提供服務,可最近使用者程式太多,導致我的服務程式有時候響應跟不上。我有點擔心這會給系統穩定性造成影響。”

我一聽,這可是個大事,系統不穩定那還得了?排程演演算法得換!

既然要讓作業系統的服務得到足夠的執行資源,那就,乾脆讓他們具有最高的 CPU 使用優先權吧。

優先順序排程演演算法就此產生了。

我向大家做出了規定——每個程式將被賦予一個優先順序,自己根據自己的情況確定優先順序數值,但是,使用者程式的優先順序不準高於核心程式的優先順序。

切換程式的時候,我會從優先順序 1 的佇列裡選擇一個程式,如果優先順序 1 佇列為空,才會選擇優先順序 2 中的程式,以此類推。

當然,為了保證低優先順序程式不會飢餓,我會調高等待時間長的程式的優先順序。

使用這個演演算法,我更忙碌了,不僅需要大量切換程式,還需要動態調節優先順序。可能這就是能力越大,責任越大吧。

不過我知道,正是因為我的存在,人類才能在計算機上執行多道程式——這令我感到自豪。

希望你在看完我的文章之後有所收穫。

感謝你的閱讀,我們後會有期!

宣告:原創文章,未經授權,禁止轉載