操作系统-进程调度
工作負(fù)載
確定工作負(fù)載是構(gòu)建調(diào)度策略的關(guān)鍵部分。工作負(fù)載了解得越多,你的策略就越優(yōu)化。
我們對操作系統(tǒng)中運(yùn)行的進(jìn)程(有時也叫工作任務(wù))做出如下的假設(shè):
1.每一個工作運(yùn)行相同的時間。
2.所有的工作同時到達(dá)。
3.一旦開始,每個工作保持運(yùn)行直到完成。
4.所有的工作只是用 CPU(即它們不執(zhí)行 IO 操作)。
5.每個工作的運(yùn)行時間是已知的。
調(diào)度的指標(biāo)
調(diào)度指標(biāo)。指標(biāo)是我們用來衡量某些東西的東西,在進(jìn)程調(diào)度中,有一些不同的指標(biāo)是有意義的。只用一個指標(biāo):周轉(zhuǎn)時間(turnaround time)。任務(wù)的周轉(zhuǎn)時間定義為任務(wù)完成時間減去任務(wù)到達(dá)系統(tǒng)的時間。更正式的周轉(zhuǎn)時間定義 T 周轉(zhuǎn)時間是:
T 周轉(zhuǎn)時間= T 完成時間?T 到達(dá)時間
因?yàn)槲覀兗僭O(shè)所有的任務(wù)在同一時間到達(dá),那么 T 到達(dá)時間= 0,因此 T 周轉(zhuǎn)時間= T 完成時間。
調(diào)度算法
先進(jìn)先出(FIFO)
先進(jìn)先出(First In First Out 或 FIFO)調(diào)度,有時候也稱為先到先服務(wù)(First Come First Served 或 FCFS)。
1:看一個簡單的例子。想象一下,3 個工作 A、B 和 C 在大致相同的時間(T 到達(dá)時間 = 0)到達(dá)系統(tǒng)。因?yàn)?FIFO 必須將某個工作放在前面,所以我們假設(shè)當(dāng)它們都同時到達(dá)時,A 比 B 早一點(diǎn)點(diǎn),然后 B 比 C 早到達(dá)一點(diǎn)點(diǎn)。假設(shè)每個工作運(yùn)行 10s。這些工作的平均周轉(zhuǎn)時間是多少?
A 在 10s 時完成,B 在 20s 時完成,C 在 30s 時完成。因此,這 3個任務(wù)的平均周轉(zhuǎn)時間就是(10 + 20 + 30)/ 3 = 20。計(jì)算周轉(zhuǎn)時間就這么簡單。
2:再次假設(shè) 3 個任務(wù)(A、B 和 C),但這次 A 運(yùn)行100s,而 B 和 C 運(yùn)行 10s。如果A先到達(dá)A 先運(yùn)行 100s,B 或 C 才有機(jī)會運(yùn)行。因此,系統(tǒng)的平均周轉(zhuǎn)時間是比較高的:令人不快的 110s((100 + 110 + 120)/ 3 = 110)。
最短任務(wù)優(yōu)先(SJF)
先運(yùn)行最短的任務(wù),然后是次短的任務(wù),如此下去。
我們用上面的例子,但以 SJF 作為調(diào)度策略。僅通過在 A 之前運(yùn)行B 和 C,SJF 將平均周轉(zhuǎn)時間從 110s 降低到 50s((10 + 20 + 120)/3 = 50)。考慮到所有工作同時到達(dá)的假設(shè),我們可以證明 SJF 確實(shí)是一個最優(yōu)(optimal)調(diào)度算法。
我們可以針對假設(shè) 2,現(xiàn)在假設(shè)工作可以隨時到達(dá),而不是同時到達(dá)。這導(dǎo)致了什么問題?
假設(shè) A 在 t = 0 時到達(dá),且需要運(yùn)行 100s。而 B 和 C 在 t = 10 到達(dá),且各需要運(yùn)行 10s。用純 SJF如下圖。
即使 B 和 C 在 A 之后不久到達(dá),它們?nèi)匀槐黄鹊鹊?A 完成,從而遭遇同樣的護(hù)航問題。這 3 項(xiàng)工作的平均周轉(zhuǎn)時間為 103.33s,即(100+(110?10)+(120?10))/3。
最短完成時間優(yōu)先(STCF)
為了解決這個問題,需要放寬假設(shè)條件(工作必須保持運(yùn)行直到完成)。我們還需要調(diào)度程序本身的一些機(jī)制。當(dāng) B 和 C 到達(dá)時,調(diào)度程序當(dāng)然可以做其他事情:它可以搶占(preempt)工作 A,并
決定運(yùn)行另一個工作,或許稍后繼續(xù)工作 A。根據(jù)我們的定義,SJF 是一種非搶占式(non-preemptive)調(diào)度程序。
向 SJF 添加搶占,稱為最短完成時間優(yōu)先(Shortest Time-to-Completion First,STCF)或搶占式最短作業(yè)優(yōu)先(Preemptive Shortest Job First ,PSJF)調(diào)度程序。每當(dāng)新工作進(jìn)入系統(tǒng)時,它就會確定剩余工作和新工作中,誰的剩余時間最少,然后調(diào)度該工作。
因此,在我們的例子中,STCF 將搶占 A 并運(yùn)行 B 和 C 以完成。只有在它們完成后,才能調(diào)度 A 的剩余時間。
響應(yīng)時間
如果我們知道任務(wù)長度,而且任務(wù)只使用 CPU,而我們唯一的衡量是周轉(zhuǎn)時間,STCF 將是一個很好的策略。。事實(shí)上,對于許多早期批處理系統(tǒng),這些類型的調(diào)度算法有一定的意義。然而,引入分時系統(tǒng)改變了這一切。要求系統(tǒng)的交互性好。
新的度量標(biāo)準(zhǔn)誕生了:響應(yīng)時間(response time)。響應(yīng)時間定義為從任務(wù)到達(dá)系統(tǒng)到首次運(yùn)行的時間。更正式的定義是: T 響應(yīng)時間= T 首次運(yùn)行?T 到達(dá)時間
例如,如果我們有上面的調(diào)度(A 在時間 0 到達(dá),B 和 C 在時間 10 達(dá)到),每個作業(yè)的響應(yīng)時間如下:作業(yè) A 為 0,B 為 0,C 為 10(平均:3.33)。
STCF 和相關(guān)方法在響應(yīng)時間上并不是很好。例如,如果 3 個工作同時到達(dá),第三個工作必須等待前兩個工作全部運(yùn)行后才能運(yùn)行。這種方法雖然有很好的周轉(zhuǎn)時間,但對于響應(yīng)時間和交互性是相當(dāng)糟糕的。 例如:你在終端前輸入,不得不等待10s才能看到系統(tǒng)的回應(yīng)。
輪轉(zhuǎn) RR
基本思想很簡單:RR 在一個時間片(time slice,有時稱為調(diào)度量子,scheduling quantum)內(nèi)運(yùn)行一個工作,然后切換到運(yùn)行隊(duì)列中的下一個任務(wù),而不是運(yùn)行一個任務(wù)直到結(jié)束。它反復(fù)執(zhí)行,直到所有任務(wù)完成。
假設(shè) 3 個任務(wù) A、B 和 C 在系統(tǒng)中同時到達(dá),并且它們都希望運(yùn)行 5s。SJF 調(diào)度程序必須運(yùn)行完當(dāng)前任務(wù)才可運(yùn)行下一個任務(wù)相比之下左側(cè)圖,1s 時間片的 RR 可以快要地循環(huán)工作 右側(cè)圖
RR 的平均響應(yīng)時間是:(0 + 1 + 2)/3 = 1; SJF 算法平均響應(yīng)時間是:(0 + 5 + 10)/ 3 = 5。
時間片長度對于 RR 是至關(guān)重要的。越短,RR 在響應(yīng)時間上表現(xiàn)越好。然而時間片太短是有問題的:突然上下文切換的成本將影響整體性能。因此需要失去足夠長,上下文切換的成本,而又不會使系統(tǒng)不及時響應(yīng)。
因?yàn)橹苻D(zhuǎn)時間只關(guān)心作業(yè)何時完成,RR 幾乎是最差的,在很多情況下甚至比簡單的 FIFO 更差。任何公平(fair)的政策(如 RR),即在小規(guī)模的時間內(nèi)將 CPU 均勻分配到活動進(jìn)程之間,在周轉(zhuǎn)時間這類指標(biāo)上表現(xiàn)不佳。事實(shí)上,這是固有的權(quán)衡:如果你愿意不公平,你可以運(yùn)行較短的工作直到完成,但是要以響應(yīng)時間為代價。如果你重視公平性,則響應(yīng)時間會較短,但會以周轉(zhuǎn)時間為代價。
第一種類型(SJF、STCF)優(yōu)化周轉(zhuǎn)時間,但對響應(yīng)時間不利。第二種類型(RR)優(yōu)化響應(yīng)時間,但對周轉(zhuǎn)時間不利。
假設(shè) 4(作業(yè)沒有 I/O)和假設(shè) 5(每個作業(yè)的運(yùn)行時間是已知的)。
結(jié)合IO:
假設(shè) 4:當(dāng)然所有程序都執(zhí)行 I/O。沒有任何輸入的程序:每次都會產(chǎn)生相同的輸出。設(shè)想一個沒有輸出的程序:沒有人看到它。它的運(yùn)行并不重要。
調(diào)度程序顯然要在工作發(fā)起 I/O 請求時做出決定,因?yàn)楫?dāng)前正在運(yùn)行的作業(yè)在 I/O 期間不會使用 CPU,它被阻塞等待 I/O 完成。如果將 I/O 發(fā)送到硬盤驅(qū)動器,則進(jìn)程可能會被阻塞幾毫秒或更長時間,具體取決于驅(qū)動器當(dāng)前的 I/O 負(fù)載。調(diào)度程序還必須在 I/O 完成時做出決定。發(fā)生這種情況時,會產(chǎn)生中斷,操作系統(tǒng)運(yùn)行并將發(fā)出 I/O 的進(jìn)程從阻塞狀態(tài)移回就緒狀態(tài)。
假設(shè)有兩項(xiàng)工作 A 和 B,每項(xiàng)工作需要 50ms 的 CPU時間。但是,有一個明顯的區(qū)別:A 運(yùn)行 10ms,然后發(fā)出 I/O 請求(假設(shè) I/O 每個都需要10ms),而 B 只是使用 CPU 50ms,不執(zhí)行 I/O。調(diào)度程序先運(yùn)行 A,然后運(yùn)行 B
將 A 的每個 10ms 的子工作視為一項(xiàng)獨(dú)立的工作它的選擇是調(diào)度 10ms 的 A,還是 50ms 的 B。對于STCF,選擇是明確的:選擇較短的一個,在這種情況下是 A。然后,A 的工作已完成,只剩下 B,并開始運(yùn)行。然后提交 A的一個新子工作,它搶占 B 并運(yùn)行 10ms。一個進(jìn)程在等待另一個進(jìn)程的 I/O 完成時使用 CPU,系統(tǒng)因此得到更好的利用
調(diào)度程序可能如何結(jié)合 I/O。通過將每個 CPU 突發(fā)作為一項(xiàng)工作,調(diào)度程序確保“交互”的進(jìn)程經(jīng)常運(yùn)行。
簡單總結(jié):第一類是運(yùn)行最短的工作,從而優(yōu)化周轉(zhuǎn)時間。第二類是交替運(yùn)行所有工作,從而優(yōu)化響應(yīng)時間。如何將 I/O 結(jié)合到場景中,但仍未解決操作系統(tǒng)根本無法看到未來的問題。
多級反饋隊(duì)列
多級反饋隊(duì)列需要解決兩方面的問題。首先,它要優(yōu)化周轉(zhuǎn)時間。通過先執(zhí)行短工作來實(shí)現(xiàn)。然而,操作系統(tǒng)通常不知道工作要運(yùn)行多久,而這又是SJF(或 STCF)等算法所必需的。MLFQ 希望給交互用戶很好的交互體驗(yàn),因此需要降低響應(yīng)時間。然而,像輪轉(zhuǎn)這樣的算法雖然降低了響應(yīng)時間,周轉(zhuǎn)時間卻很差。
MLFQ:基本規(guī)則
- 規(guī)則 1:如果 A 的優(yōu)先級 > B 的優(yōu)先級,運(yùn)行 A(不運(yùn)行 B)。
- 規(guī)則 2:如果 A 的優(yōu)先級 = B 的優(yōu)先級,輪轉(zhuǎn)運(yùn)行 A 和 B。
- 規(guī)則 3:工作進(jìn)入系統(tǒng)時,放在最高優(yōu)先級(最上層隊(duì)列)。
- 規(guī)則 4:一旦工作用完了其在某一層中的時間配額(無論中間主動放棄了多少次CPU),就降低其優(yōu)先級(移入低一級隊(duì)列)。
- 規(guī)則 5:經(jīng)過一段時間 S,就將系統(tǒng)中所有工作重新加入最高優(yōu)先級隊(duì)列。
MLFQ 中有許多獨(dú)立的隊(duì)列(queue),每個隊(duì)列有不同的優(yōu)先級(priority level)。任何時刻,一個工作只能存在于一個隊(duì)列中。MLFQ 總是優(yōu)先執(zhí)行較高優(yōu)先級的工作。每個隊(duì)列中可能會有多個工作,因此具有同樣的優(yōu)先級。
MLFQ 沒有為每個工作指定不變的優(yōu)先而已根據(jù)觀察到的行為調(diào)整它的優(yōu)先級。如果一個工作不斷放棄CPU 去等待鍵盤輸入,這是交互型進(jìn)程的可能行為,MLFQ 因此會讓它保持高優(yōu)先級。如果一個工作長時間地占用 CPU,MLFQ 會降低其優(yōu)先級。
如何改變優(yōu)先級:就是上述的規(guī)則3 4. 假設(shè)一個工作200ms,3級隊(duì)列:該工作首先進(jìn)入最高優(yōu)先級(Q2)。執(zhí)行一個 10ms 的時間片后,調(diào)度程序?qū)⒐ぷ鞯膬?yōu)先級減 1,因此進(jìn)入 Q1。在 Q1 執(zhí)行一個時間片后,最終降低優(yōu)先級進(jìn)入系統(tǒng)的最低優(yōu)先級(Q0),一直留在那里。
如何提升優(yōu)先級:簡單的思路是周期性地提升所有工作的優(yōu)先級。將所有工作扔到最高優(yōu)先級隊(duì)列。(規(guī)則5),那么S 怎么設(shè)置?如果 S 設(shè)置得太高,長工作會饑餓;如果設(shè)置得太低,交互型工作又得不到合適的 CPU 時間比例。
MLFQ的其他問題
如何配置一個調(diào)度程序,例如,配置多少隊(duì)列?每一層隊(duì)列的時間片配置多大?為了避免饑餓問題以及進(jìn)程行為改變,應(yīng)該多久提升一次進(jìn)程的優(yōu)先級?
大多數(shù)的 MLFQ 變體都支持不同隊(duì)列可變的時間片長度。高優(yōu)先級隊(duì)列通常只有較短的時間片(比如 10ms 或者更少),因而這一層的交互工作可以更快地切換。相反,低優(yōu)先級隊(duì)列中更多的是 CPU 密集型工作,配置更長的時間片會取得更好的效果。
總結(jié):多級反饋隊(duì)列(MLFQ)。—它有多級隊(duì)列,并利用反饋信息決定某個工作的優(yōu)先級。關(guān)注進(jìn)程
的一貫表現(xiàn),然后區(qū)別對待。
它不需要對工作的運(yùn)行方式有先驗(yàn)知識,而是通過觀察工作的運(yùn)行來給出對應(yīng)的優(yōu)先級。通過這種方式,MLFQ 可以同時滿足各種工作的需求:對于短時間運(yùn)行的交互型工作,獲得類似于 SJF/STCF 的很好的全局性能,同時對長時間運(yùn)行的CPU 密集型負(fù)載也可以公平地、不斷地穩(wěn)步向前。
多級處理器調(diào)度
必須先知道它與單 CPU 之間的基本區(qū)別。區(qū)別的核心在于對硬件緩存(cache)的使用以及多處理器之間共享數(shù)據(jù)的方式。
在單 CPU 系統(tǒng)中,存在多級的硬件緩存,一般來說會讓處理器更快地執(zhí)行程序。緩存是很小但很快的存儲設(shè)備,通常擁有內(nèi)存中最熱的數(shù)據(jù)的備份。相比之下,內(nèi)存很大且擁有所有的數(shù)據(jù),但訪問速度較慢。通過將頻繁訪問的數(shù)據(jù)放在緩存中,系統(tǒng)似乎擁有又大又快的內(nèi)存。
假設(shè)一個程序需要從內(nèi)存中加載指令并讀取一個值,CPU1個,較小的緩存和較大的內(nèi)存。
程序第一次讀取數(shù)據(jù)時,數(shù)據(jù)在內(nèi)存中,因此需要花費(fèi)較長的時間處理器判斷該數(shù)據(jù)很可能會被再次使用,因此將其放入 CPU 緩存中。如果之后程序再次需要使用同樣的數(shù)據(jù),CPU 會先查找緩存。因?yàn)樵诰彺嬷姓业搅藬?shù)據(jù),所以取數(shù)據(jù)快得多(比如幾納秒),程序也就運(yùn)行更快。
緩存是基于局部性的概念,局部性有兩種,即時間局部性和空間局部性。時間局部性是指當(dāng)一個數(shù)據(jù)被訪問后,它很有可能會在不久的將來被再次訪問,比如循環(huán)代碼中的數(shù)據(jù)或指令本身。而空間局部性指的是,當(dāng)程序訪問地址為 x 的數(shù)據(jù)時,很有可能會緊接著訪問 x 周圍的數(shù)據(jù),比如遍歷數(shù)組或指令的順序執(zhí)行。
如果系統(tǒng)有多個處理器,并共享同一個內(nèi)存如上圖右側(cè)。
多 CPU 的情況下緩存要復(fù)雜得多。假設(shè)一個運(yùn)行在 CPU 1 上的程序從內(nèi)存地址 A 讀取數(shù)據(jù)。由于不在 CPU 1 的緩存中,所以系統(tǒng)直接訪問內(nèi)存,得到值 D。程序然后修改了地址 A 處的值,只是將它的緩存更新為新值 D’。將數(shù)據(jù)寫回內(nèi)存比較慢,因此系統(tǒng)(通常)會稍后再做。假設(shè)這時操作系統(tǒng)中斷了該程序的運(yùn)行,并將其交給 CPU 2,重新讀取地址 A 的數(shù)據(jù),由于 CPU 2 的緩存中并沒有該數(shù)據(jù),所以會直接從內(nèi)存中讀取,得到了舊值 D,而不是正確的值 D’。
這一普遍的問題稱為緩存一致性問題。
硬件提供了這個問題的基本解決方案:通過監(jiān)控內(nèi)存訪問,硬件可以保證獲得正確的數(shù)據(jù),并保證共享內(nèi)存的唯一性。在基于總線的系統(tǒng)中,一種方式是使用總線窺探每個緩存都通過監(jiān)聽鏈接所有緩存和內(nèi)存的總線,來發(fā)現(xiàn)內(nèi)存訪問。如果 CPU 發(fā)現(xiàn)對它放在緩存中的數(shù)據(jù)的更新,會作廢本地副本(從緩存中移除),或更新它(修改為新值)。
跨 CPU 訪問共享數(shù)據(jù)或數(shù)據(jù)結(jié)構(gòu)時,需要使用互斥原語才能保證正確性其他方法偶爾才使用。
單隊(duì)列調(diào)度
單隊(duì)列多處理器調(diào)度 SQMS 它不需要太多修改,就可以將原有的策略用于多個 CPU,選擇最適合的工作來運(yùn)行.
短板:第一個是缺乏可擴(kuò)展性。為了保證在多CPU 上正常運(yùn)行,調(diào)度程序的開發(fā)者需要在代碼中通過加鎖(locking)來保證原子性。在 SQMS 訪問單個隊(duì)列時(如尋找下一個運(yùn)行的工作),鎖確保得到正確的結(jié)果。鎖可能帶來巨大的性能損失,尤其是隨著系統(tǒng)中的 CPU 數(shù)增加時.隨著這種單個鎖的爭用增加,系統(tǒng)花費(fèi)了越來越多的時間在鎖的開銷上,較少的時間用于系統(tǒng)應(yīng)該完成的工作。
SQMS 的第二個主要問題是緩存親和性。盡可能讓進(jìn)程在同一個 CPU 上運(yùn)行。保持一些工作的親和度的同時,可能需要犧牲其他工作的親和度來實(shí)現(xiàn)負(fù)載均衡。
多隊(duì)列調(diào)度
每個 CPU一個隊(duì)列。我們稱之為多隊(duì)列多處理器調(diào)度 MQMS
MQMS 中,基本調(diào)度框架包含多個調(diào)度隊(duì)列,每個隊(duì)列可以使用不同的調(diào)度規(guī)則,比如輪轉(zhuǎn)或其他任何可能的算法。
假設(shè)系統(tǒng)中有兩個 CPU(CPU 0 和 CPU 1)。這時一些工作進(jìn)入系統(tǒng):A、B、C 和 D。由于每個 CPU 都有自己的調(diào)度隊(duì)列,操作系統(tǒng)需要決定每個工作放入哪個隊(duì)列。根據(jù)不同隊(duì)列的調(diào)度策略,每個 CPU 從兩個工作中選擇,決定誰將運(yùn)行。
MQMS 比 SQMS 有明顯的優(yōu)勢,它天生更具有可擴(kuò)展性。隊(duì)列的數(shù)量會隨著 CPU 的增加而增加,因此鎖和緩存爭用的開銷不是大問題。此外,MQMS 天生具有良好的緩存親和度。所有工作都保持在固定的 CPU 上,因而可以很好地利用緩存數(shù)據(jù)。
負(fù)載不均 :假設(shè)4個任務(wù)2個CPU,ABCD,假設(shè)C指向完了,然后 Q0->A Q1-> BD 那么就是CPU0 ->A CPU1->B D A也完成的話 那么 CPU0 -> CPU1->BD
解決是:工作竊取! 工作量較少的(源)隊(duì)列不定期地“偷看”其他(目標(biāo))隊(duì)列是不是比自己的工作多。如果目標(biāo)隊(duì)列比源隊(duì)列(顯著地)更滿,就從目標(biāo)隊(duì)列“竊取”一個或多個工作,實(shí)現(xiàn)負(fù)載均衡。
總結(jié)
- 上一篇: HCNE知识点总结
- 下一篇: 【Go语言】实现一个简单的纯后端学员管理