CPU Sched - CPU 調度

Introduction

本文將介紹 CPU 高級策略之 CPU 調度,針對一系列調度策略展開。

THE CRUX

Q:
 如何制定調度策略?

  1. 如何開發一個基本框架考慮調度策略?
  2. 需要做哪些關鍵的假設?
  3. 哪些指標是最重要的?
  4. 最早的計算機使用的基本方法?

工作量假設 [Workload Assumptions]

在開始介紹策略之前,首先對系統中運行的進程 (或稱爲工作量) 做一些假設。

確定工作量是建立策略的步驟中最重要的部分

假設如下:

Hint: 這些看似不可行的假設,在之後的介紹中會放寬要求,簡化了全業務調度的開發

  1. 所有進程的運行時間相同;
  2. 所有進程同時到達等待啓動;
  3. 一旦開始,所有進程終將進行完整的運行流程;
  4. 所有的進程均只利用 CPU(不執行任何 I/O)
  5. 每個進程的運行時間已知

調度指標 [Scheduling Metrics]

我們需要一樣東西來衡量不同的調度策略,即調度指標

設定一個簡單的指標:Turnaround Time (理解爲 “週轉時間” ), 其定義爲進程完成的時刻減去到達等待開始的時刻:

Tturnaround=TcompletionTarrival T_{turnaround } = T_{completion} - T_{arrival}

在工作量假設中有一條假設:所有進程同時等待啓動,所以 Tarrival=0T_{arrival} = 0 ,進一步,Tturnaround=TcompletionT_{turnaround } = T_{completion}。也就是說放寬假設的要求,這個觀點就會改變。

生活不總是完美的

注意到,週轉時間是一個性能指標,由此不得不再設定一個指標,Fairness (理解爲公平性)


在調度中,性能公平性常常是不一致

For Example:調度程序可以優化性能,但代價是阻止一些作業運行,從而降低公平性。


先進先出(FIFO)

FIFO 的優點在於簡單易實現

我們可以實現的最基本的算法是先進先出調度 ( 亦被稱爲 First Come, First Served - FCFS )

For Example:

    假設系統中有三個進程,A、B和C,大致同時到達(Tarrival=0T_{arrival}= 0)。因爲 FIFO 必須把某個進程放在第一位執行。假設當它們同時到達時,A在B之前到達,而B在C之前到達。同時假設每個進程運行10秒。這些工作的平均週轉時間將是多少?

圖中模擬了進程執行時間,A 在10 的位置完成,B 在20 的位置完成,C 在30 的位置完成

那麼,平均週轉時間計算爲:

10+20+303=20 {\frac{10+20+30}{3}} = 20

問題來了:

如果我們放寬第一個假設的要求,不再假設每個進程的運行時間相同。

  1. 這種情形下,FIFO 如何運行?
  2. 如何構建工作量,會導致 FIFO 性能崩潰?

我們繼續通過例子模擬進程的運行時間,以及不同運行時間的進程如何搞垮 FIFO

For Example:

    接着之前的三個進程 A、B、C,與上次不同的是 A 運行時間爲100,B、C均爲10

模擬結果:

B、C 在運行之前先等待 A 運行 100,這樣,平均週轉時間計算爲:

100+110+1203=110 {\frac{100+110+120}{3}} = 110

一些資源較短的潛在消費者排在一些重量級資源消費者的後面,這便是經典的護航效應 (convoy effect)

Q:

  怎樣才能開發出一個更好的算法來處理運行時間不同的進程呢?

Shortest Job First - SJF

是一個通用的調度原則,它可以應用於任何系統

特點是:每個進程的週轉時間平等重要

憶上個學期運籌學中的運輸問題解決辦法->最短作業法事實上,這個方法可以應用於計算機系統中的工作調度。

這個新的調度規則稱爲最短作業優先 (最短作業優先),其名稱應該很容易記住,因爲它非常完整地描述了策略: 首先運行最短作業,然後運行下一個最短作業,以此類推。

接着前面的例子重新模擬,平均週轉時間計算爲:

10+20+1203=50 {\frac{10+20+120}{3}} = 50

[110>50] [110->50 ]

理論上,如果假設進程同時到達成立,那麼可以證明 SJF 是一個最優調度算法【實際中,非也】

問題來了:

  針對假設2,對其要求再進一步放寬,讓進程隨機到達,而不是同時,會出現什麼狀況?

For Example:

  假設 A 在 t = 0 時刻到達,需要運行 100 ,而 B 和 C 在 t = 10 到達,每個需要運行 10 。

模擬結果:

B、C 在 A 開始運行後到達,出現了和之前相同的護航效應,此時,平均週轉時間計算爲:

100+(11010)+(12010)3=103.33... {\frac{100+(110-10)+(120-10)}{3}} = 103.33...

Q:
  調度究竟能做什麼?
A:
  爲了解決新出現的問題,接下來考慮放寬假設 3 的要求


補充:

搶佔式調度 Preemptive Schedulers

    在以前的批量計算時代,開發了許多非搶佔式調度程序,這種系統將正在運行的進程運行完畢才考慮要不要運行下一個新的進程,幾乎所有的現代調度程序都是搶佔式的,並且會爲了運行另一個進程而停止一個進程的運行。

    這意味着調度程序採用了我們之前瞭解到的機制;特別是,調度程序可以執行上下切換,暫時停止一個正在運行的進程,並恢復(或啓動)另一個進程。


根據調度的本身機制,考慮到計時器中斷和上下切換,當 B 和C到達時,調度器會做一些其他的事情:搶佔 A 的運行時間並運行其他進程,或者決定先暫停稍後再運行。而 SJF 是一個非搶佔式調度程序,因此無法改變平均週轉時間仍然很的現狀。

那麼可否將搶佔機制加到 SJF 中呢,這樣就可以完善了?答案是可以的,添加後的結果稱爲最短完成時間優先(STCF)或搶佔最短作業優先(PSJF)調度程序

SJF
+
搶佔機制
||
STCF

Shortest Time-to-Completion First (STCF)

放寬假設3的要求,進程不必要一旦開始就定要執行完畢

每當新進程進入系統時,STCF調度器確定剩餘進程 (包括新進程) 中剩餘時間最少的進程,並調度該進程。

STCF將搶佔 A 並運行 B 和 C 直到完成;只有當它們完成時,纔會安排 A 的剩餘時間。如此,平均週轉時間計算爲:

(1200)+(2010)+(3010)3=50 {\frac{(120-0)+(20-10)+(30-10)}{3}} = 50

和之前一樣,考慮到我們的新假設,STCF是可證明最優的;考慮到如果所有工作同時到達,SJF是最優的。

However:

    如果我們知道進程運行時間長度、進程僅需要 CPU,並且唯一的度量指標是週轉時間,可以確定 STCF 是最優的調度策略。但是隨着分時機的引入,用戶在終端中也可以與系統進行交互。

    出現了交互,我們需要引入一個新的度量指標:響應時間。

響應時間 [A New Metric: Response Time]

從進程到達系統到它第一次被調度的時間

Tresponse=TfirstrunTarrival T_{response} = T_{firstrun} - T_{arrival}

利用之前的調度例子:

    不同的是 A 在時間 0 時到達,B 和 C 在時間 10 時到達,每個進程的響應時間如下 : A爲0,B爲0,C爲10,響應時間平均值爲 3.33

可以看出:STCF及其相關並不利於優化響應時間。

For Example:

如果三個作業同時到達,那麼第三個作業必須等待前兩個作業全部運行,然後才進行一次調度。雖然這種方法對於週轉時間很好,但是對於響應時間和交互性卻很差。

實際上,現實生活中,終端前打字,不得不等上 10 秒鐘才能看到系統的響應,因爲在這之前有其他的進程已經被調度。

Q:

那麼我們該如何構建一個對響應時間敏感的調度器?

A:

引入新的調度算法-> Round Robin

輪詢法 [Round Robin]

負載均衡算法【簡稱 RR】

RR 不再是一旦運行開始就必須運行完畢,而是運行一個時間片( 亦稱爲調度量 ),接着切換到運行隊列中的下一個進程,反覆這樣做,直到所有工作完成。所以有時候 RR 冠之以時間切片的稱號。

注意: 時間片的長度必須是計時器中斷週期的倍數;因此,如果計時器每10毫秒中斷一次,則時間片可以是10、20或任何其他10毫秒的倍數。

還是通過例子以達到對 RR 的徹底理解:

For Example:

假設A、B、C三個進程同時到達,並且每一個進程都希望運行 5 個時間單位。

一個 SJF 調度器就像之前介紹的一樣在運行一個新的進程之前保證正在運行的進程運行完畢。

平均響應時間:(0+5+10) / 3 = 5

相比之下,RR 按照 1 個時間單位的時間片可以很高效的完成所有任務。

平均響應時間:(0+1+2) / 3 = 1
  • 如上對比: 時間片的長度對於 RR 來說是至關重要的。它越短,在響應時間度量下 RR 的性能越好

  • 但是 ,盲目得讓時間片太短是有問題的,突發的上下文切換帶來的開銷將主導整體性能。

  • 因此決定時間片的長度對系統設計人員來說是一種權衡。目的是使其有足夠長的時間來攤銷切換的成本,同時又不會使其太長而導致系統不再響應

注意: 上下文切換的開銷並不僅僅來自於OS保存和恢復幾個寄存器的操作。當程序運行時,它們會在CPU緩存、緩存器、分支預測器和其他片上硬件中建立大量的狀態。切換到另一個作業會導致刷新此狀態並引入與當前正在運行的進程相關的新狀態,這可能會導致顯著的性能損失】


補充:

攤銷可以降低成本 [Amortization can Reduce Costs]

    某項固定的開銷產生時,往往伴隨着系統中的攤銷技術的體現。通過減少成本(即減少操作次數),降低了系統的總成本。

For Example:

  • 如果時間片設置爲10毫秒,而上下文切換成本爲1毫秒,則大約10%的時間用於上下文切換,均被浪費;

  • 如果我們想分攤這個成本,可以增加時間片到 100 毫秒。在這種情況下,不到 1% 的時間用於上下文切換,這樣一來,時間成本得到了攤銷。


沒有對比就沒有傷害

  • 如果響應時間是我們唯一的度量,那麼具有合理時間片的RR就是一個非常好的調度器。

  • 還記得之前我們以週轉時間爲唯一度量,那麼在 RR 的例子的基礎上,運行時間分別爲 5 秒的 A、B和 C 同時到達,RR 是具有 1 個單位長時間片的調度器。從上面的圖中我們可以看到,A結束於13,B結束於14,C結束於15,平均週轉時間爲14。

因此,如果週轉時間是我們的度量標準,那麼 RR 確實是最糟糕的策略之一也就不足爲奇了。

從直覺上看: RR所做的就是儘可能地延長每個作業的執行時間,在執行下一個作業之前,只運行一小段時間。因爲週轉時間只關心作業何時完成,所以 RR 在特定情況下比 FIFO 的效果都差。

魚與熊掌不可兼得

說白了就是:權衡

任何公平的策略(如 RR),即在小時間尺度上將 CPU 平均分配給活動進程的策略,相應的在週轉時間等指標上都會表現不佳。

事實上,這是一種內在的權衡 。當然,你也可以運行更短的作業到完成,但代價是響應時間;如果你重視公平,則響應時間會降低,但代價是週轉時間。


補充:

重疊操作可提高系統的利用率

    在儘可能的情況下,重疊操作得以最大限度地利用系統。重疊在許多不同的域中都很有用,包括在執行磁盤 I/O 或向遠程計算機發送消息時;

    在這兩種情況下,啓動操作然後切換到另一個工作空間,可以提高系統的總體利用率和效率。


至此,需要進行總結…

Summary

我們認知了兩種類型的調度策略:【就兩個度量指標進行對比】

  • 第一種類型(SJF,STCF)優化了週轉時間,但對響應時間不利。

  • 第二種類型(RR)優化了響應時間,但不利於週轉。

試回想 5 個假設,我們已經涉及到了前三個假設,並且都進行了需求更改。

接下來,需要進一步面對剩餘兩個假設…

Incorporating I/O

針對假設 4 :所有的進程均只利用 CPU(不執行任何 I/O)

對於假設 4 ,當然正常情況下所有程序都執行I/O。

  • 設想一個不接受任何輸入的程序,它每次都將會產生相同的輸出;

  • 再想象一個沒有輸出的程序,那麼它有沒有在運行似乎已經變得無關緊要。

當一個進程啓動一個I/O請求時,調度器顯然具有決策權。因爲當前運行的進程在 I/O 期間不會使用CPU,它在等待 I/O 完成時被阻塞。

如果 I/O 是輸出到硬盤驅動器,進程可能會被阻塞幾毫秒甚至更長時間,具體取決於驅動器的當前 I/O 負載。從而,調度器可能在 CPU 上調度另一個進程。

具有決策權的調度器還必須在 I/O 完成時做出決定。做決定時會引發中斷,操作系統運行並將請求 I/O 的進程從阻塞狀態移回就緒狀態。當然,它甚至也可以決定在那時進行這個任務。

Q:
那麼,對待每一個進程,可以重新開始也可以繼續進行,操作系統應該如何對待每項工作?
A:
e.g. 假設有兩個進程,A 和 B,每個進程都需要50毫秒的計算時間。區別在於,A 運行10毫秒,然後發出一個I/O請求( 這裏假設每個I/O需要10毫秒 ),而 B 只使用50毫秒計算時間,不執行I/O。這種情形下,調度器會先運行A,然後運行B。

Q:
 假設我們用的調度器是STCF調度程序。那麼應該如何解釋?
A:
 a 被分解成5個10毫秒的子作業,而B只是一個50毫秒的 CPU 需求,很顯然,只需要運行一個進程,對於另一個沒有把 I/O 考慮在內的進程是沒有意義的。

另一種常見的方法是將 A 的每個 10ms 子作業視爲獨立作業。

因此,當系統啓動時,其選擇是調度 10 ms A還是 50 ms B。對於STCF,顯然是選擇較短的一個。當 A 的第一個子作業完成時,只剩下 B,它開始運行。然後提交一個新的 A 子作業,它搶佔 B 並運行 10 ms。這樣做允許重疊,一個進程使用CPU,同時等待另一個進程的 I/O 完成;高效的利用了 CPU。

Summary:

   通過這種新的方法,我們可以看到調度器如何合併 I/O。將每個 CPU 突發當作一個作業來處理,調度器確保 “交互式” 運行。當這些交互作業執行 I/O 時,其他CPU密集型作業也會運行,從而更好地利用處理器。

No More Oracle

基於 合併 I/O 方法,我們就可以得到最後的假設,調度器知道每個作業的長度。正如我們之前所說,這可能是我們能做出的最不切實際的假設。事實上,在一個通用操作系統(就像我們關心的那些操作系統)中,操作系統通常對每個作業的長度知之甚少。

Summary

此文介紹了調度背後的基本思想,並開發了兩種方法。第一個運行剩餘的最短作業,從而優化週轉時間;第二個在所有作業之間交替,從而優化響應時間。內在均衡問題導致無法判別某一種方法的絕對好壞。

我們也看到了如何將I/O集成到圖片中,但仍然沒有解決操作系統無法預見未來的問題。

經典 Q:
    因此,如果沒有這樣的先驗知識,我們怎麼能建立一個像SJF/STCF這樣的方法呢?此外,我們如何將我們看到的一些想法與RR調度器結合起來,從而使響應時間也相當好?

A:
    通過構建一個調度程序,使用最近的過去來預測未來。這個調度程序稱爲多級反饋隊列,見下回分曉…

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