您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Linux的進程優先級NI和PR有哪些區別呢,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
為什么要有進程優先級?
這似乎不用過多的解釋,畢竟自從多任務操作系統誕生以來,進程執行占用cpu的能力就是一個必須要可以人為控制的事情。因為有的進程相對重要,而有的進程則沒那么重要。
進程優先級起作用的方式從發明以來基本沒有什么變化,無論是只有一個cpu的時代,還是多核cpu時代,都是通過控制進程占用cpu時間的長短來實現的。
就是說在同一個調度周期中,優先級高的進程占用的時間長些,而優先級低的進程占用的短些。
請大家真的不要混淆了系統中的這兩個概念:nice(NI)和priority(PR),他們有著千絲萬縷的關系,但對于當前的Linux系統來說,它們并不是同一個概念。
我們看這個命令:
大家是否真的明白其中PRI列和NI列的具體含義有什么區別?
同樣的,如果是top命令:
大家是否搞清楚了這其中PR值和NI值的差別?如果沒有,那么我們可以首先搞清楚什么是nice值。
什么是NICE值?
NICE值應該是熟悉Linux/UNIX的人很了解的概念了,它是反應一個進程“優先級”狀態的值,其取值范圍是-20至19,一共40個級別。
這個值越小,表示進程”優先級”越高,而值越大“優先級”越低。
例如,我們可以通過NICE命令來對一個將要執行的bash命令進行NICE值設置,方法是:
[root@zorrozou-pc0 zorro]# nice -n 10 bash
這樣我就又打開了一個bash,并且其nice值設置為10,而默認情況下,進程的優先級應該是從父進程繼承來的,這個值一般是0。
我們可以通過nice命令直接查看到當前shell的nice值:
[root@zorrozou-pc0 zorro]# nice 10
對比一下正常情況:
[root@zorrozou-pc0 zorro]# exit
退出當前nice值為10的bash,打開一個正常的bash,我們查看下其 Nice值:
[root@zorrozou-pc0 zorro]# bash [root@zorrozou-pc0 zorro]# nice 0
另外,使用renice命令可以對一個正在運行的進程進行nice值的調整,我們也可以使用比如top、ps等命令查看進程的nice值,具體方法我就不多說了,大家可以參閱相關man page。
需要大家注意的是,我在這里都在使用nice值這一稱謂,而非優先級(priority)這個說法。
nice值雖然不是priority,但是它確實可以影響進程的優先級。
在英語中,如果我們形容一個人nice,那一般說明這個人的人緣比較好。什么樣的人人緣好?往往是謙讓、有禮貌的人。
比如,你跟一個nice的人一起去吃午飯,點了兩個一樣的飯,先上了一份后,nice的那位一般都會說:“你先吃你先吃!”,這就是人緣好,這人nice!但是如果另一份上的很晚,那么這位nice的人就要餓著了。
這說明什么?
越nice的人搶占資源的能力就越差,而越不nice的人搶占能力就越強。這就是nice值大小的含義,nice值越低,說明進程越不nice,搶占cpu的能力就越強,優先級就越高(作者這個解釋太形象了,小編忍不住要手動點贊!!)。
在原來使用O1調度的Linux上,我們還會把nice值叫做靜態優先級,這也基本符合nice值的特點,就是當nice值設定好了之后,除非我們用renice去改它,否則它是不變的。
而priority的值在之前內核的O1調度器上表現是會變化的,所以也叫做動態優先級。
什么是優先級和實時進程?
我們再來看看什么是priority值,就是ps命令中看到的PRI值或者top命令中看到的PR值。
本文為了區分這些概念,以后:
統一用nice值表示NI值,或者叫做靜態優先級,也就是用nice和renice命令來調整的優先級;
而實用priority值表示PRI和PR值,或者叫動態優先級。
我們也統一將“優先級”這個詞的概念規定為表示priority值的意思。
在內核中,進程優先級的取值范圍是通過一個宏定義的,這個宏的名稱是MAX_PRIO,它的值為140。
而這個值又是由另外兩個值相加組成的,一個是代表nice值取值范圍的NICE_WIDTH宏,另一個是代表實時進程(realtime)優先級范圍的MAX_RT_PRIO宏。
說白了就是,Linux實際上實現了140個優先級范圍,取值范圍是從0-139,這個值越小,優先級越高。nice值的-20到19,映射到實際的優先級范圍是100-139。
新產生進程的默認優先級被定義為:
#define DEFAULT_PRIO (MAX_RT_PRIO + NICE_WIDTH / 2)
實際上對應的就是nice值的0。
正常情況下,任何一個進程的優先級都是這個值,即使我們通過nice和renice命令調整了進程的優先級,它的取值范圍也不會超出100-139的范圍,除非這個進程是一個實時進程,那么它的優先級取值才會變成0-99這個范圍中的一個。
這里隱含了一個信息,就是說當前的Linux是一種已經支持實時進程的操作系統。
什么是實時操作系統?
我們就不再這里詳細解釋其含義以及在工業領域的應用了,有興趣的可以參考一下實時操作系統的維基百科。
簡單來說,實時操作系統需要保證相關的實時進程在較短的時間內響應,不會有較長的延時,并且要求最小的中斷延時和進程切換延時。
對于這樣的需求,一般的進程調度算法,無論是O1還是CFS都是無法滿足的,所以內核在設計的時候,將實時進程單獨映射了100個優先級,這些優先級都要高于正常進程的優先級(nice值),而實時進程的調度算法也不同,它們采用更簡單的調度算法來減少調度開銷。
總的來說,Linux系統中運行的進程可以分成兩類:
實時進程
非實時進程
它們的主要區別就是通過優先級來區分的。
所有優先級值在0-99范圍內的,都是實時進程,所以這個優先級范圍也可以叫做實時進程優先級,而100-139范圍內的是非實時進程。
在系統中可以使用chrt命令來查看、設置一個進程的實時優先級狀態。我們可以先來看一下chrt命令的使用:
我們先來關注顯示出的Policy options部分,會發現系統給各種進程提供了5種調度策略。
但是這里并沒有說明的是,這五種調度策略是分別給兩種進程用的,對于實時進程可以用的調度策略是:SCHED_FIFO、SCHED_RR,而對于非實時進程則是:SCHED_OTHER、SCHED_OTHER、SCHED_IDLE。
系統的整體優先級策略是:
如果系統中存在需要執行的實時進程,則優先執行實時進程。
直到實時進程退出或者主動讓出CPU時,才會調度執行非實時進程。
實時進程可以指定的優先級范圍為1-99,將一個要執行的程序以實時方式執行的方法為:
[root@zorrozou-pc0 zorro]# chrt 10 bash [root@zorrozou-pc0 zorro]# chrt -p $$ pid 14840's current scheduling policy: SCHED_RR pid 14840's current scheduling priority: 10
可以看到,新打開的bash已經是實時進程,默認調度策略為SCHED_RR,優先級為10。如果想修改調度策略,就加個參數:
[root@zorrozou-pc0 zorro]# chrt -f 10 bash [root@zorrozou-pc0 zorro]# chrt -p $$ pid 14843's current scheduling policy: SCHED_FIFO pid 14843's current scheduling priority: 10
剛才說過,SCHED_RR和SCHED_FIFO都是實時調度策略,只能給實時進程設置。對于所有實時進程來說,優先級高的(就是priority數字小的)進程一定會保證先于優先級低的進程執行。
SCHED_RR和SCHED_FIFO的調度策略只有當兩個實時進程的優先級一樣的時候才會發生作用,其區別也是顧名思義:
SCHED_FIFO
以先進先出的隊列方式進行調度,在優先級一樣的情況下,誰先執行的就先調度誰,除非它退出或者主動釋放CPU。
SCHED_RR
以時間片輪轉的方式對相同優先級的多個進程進行處理。時間片長度為100ms。
這就是Linux對于實時進程的優先級和相關調度算法的描述。整體很簡單,也很實用。
而相對更麻煩的是非實時進程,它們才是Linux上進程的主要分類。對于非實時進程優先級的處理,我們首先還是要來介紹一下它們相關的調度算法:O1和CFS。
什么是O1調度?
O1調度算法是在Linux 2.6開始引入的,到Linux 2.6.23之后內核將調度算法替換成了CFS。
雖然O1算法已經不是當前內核所默認使用的調度算法了,但是由于大量線上的服務器可能使用的Linux版本還是老版本,所以我相信很多服務器還是在使用著O1調度器,那么費一點口舌簡單交代一下這個調度器也是有意義的。
這個調度器的名字之所以叫做O1,主要是因為其算法的時間復雜度是O1。
O1調度器仍然是根據經典的時間片分配的思路來進行整體設計的。
簡單來說,時間片的思路就是將CPU的執行時間分成一小段一小段的,假如是5ms一段。于是多個進程如果要“同時”執行,實際上就是每個進程輪流占用5ms的cpu時間,而從1s的時間尺度上看,這些進程就是在“同時”執行的。
當然,對于多核系統來說,就是把每個核心都這樣做就行了。而在這種情況下,如何支持優先級呢?
實際上就是將時間片分配成大小不等的若干種,優先級高的進程使用大的時間片,優先級小的進程使用小的時間片。這樣在一個周期結速后,優先級大的進程就會占用更多的時間而因此得到特殊待遇。
O1算法還有一個比較特殊的地方是,即使是相同的nice值的進程,也會再根據其CPU的占用情況將其分成兩種類型:CPU消耗型和IO消耗性。
典型的CPU消耗型的進程的特點是,它總是要一直占用CPU進行運算,分給它的時間片總是會被耗盡之后,程序才可能發生調度。
比如常見的各種算數運算程序。
而IO消耗型的特點是,它經常時間片沒有耗盡就自己主動先釋放CPU了。
比如vi,emacs這樣的編輯器就是典型的IO消耗型進程。
為什么要這樣區分呢?因為IO消耗型的進程經常是跟人交互的進程,比如shell、編輯器等。
當系統中既有這種進程,又有CPU消耗型進程存在,并且其nice值一樣時,假設給它們分的時間片長度是一樣的,都是500ms,那么人的操作可能會因為CPU消耗型的進程一直占用CPU而變的卡頓。
可以想象,當bash在等待人輸入的時候,是不占CPU的,此時CPU消耗的程序會一直運算,假設每次都分到500ms的時間片,此時人在bash上敲入一個字符的時候,那么bash很可能要等個幾百ms才能給出響應,因為在人敲入字符的時候,別的進程的時間片很可能并沒有耗盡,所以系統不會調度bash程度進行處理。
為了提高IO消耗型進程的響應速度,系統將區分這兩類進程,并動態調整CPU消耗的進程將其優先級降低,而IO消耗型的將其優先級變高,以降低CPU消耗進程的時間片的實際長度。
已知nice值的范圍是-20-19,其對應priority值的范圍是100-139,對于一個默認nice值為0的進程來說,其初始priority值應該是120,隨著其不斷執行,內核會觀察進程的CPU消耗狀態,并動態調整priority值,可調整的范圍是+-5。
就是說,***優先級可以被自動調整到115,***到125。這也是為什么nice值叫做靜態優先級,而priority值叫做動態優先級的原因。不過這個動態調整的功能在調度器換成CFS之后就不需要了,因為CFS換了另外一種CPU時間分配方式,這個我們后面再說。
什么是CFS完全公平調度?
O1已經是上一代調度器了,由于其對多核、多CPU系統的支持性能并不好,并且內核功能上要加入cgroup等因素,Linux在2.6.23之后開始啟用CFS作為對一般優先級(SCHED_OTHER)進程調度方法。
在這個重新設計的調度器中,時間片,動態、靜態優先級以及IO消耗,CPU消耗的概念都不再重要。CFS采用了一種全新的方式,對上述功能進行了比較完善的支持。
其設計的基本思路是:我們想要實現一個對所有進程完全公平的調度器。
又是那個老問題:如何做到完全公平?答案跟上一篇IO調度中CFQ的思路類似:
如果當前有n個進程需要調度執行,那么調度器應該在一個比較小的時間范圍內,把這n個進程全都調度執行一遍,并且它們平分cpu時間,這樣就可以做到所有進程的公平調度。
那么這個比較小的時間就是任意一個R狀態進程被調度的***延時時間,即:任意一個R狀態進程,都一定會在這個時間范圍內被調度響應。這個時間也可以叫做調度周期,其英文名字叫做:sched_latency_ns。
CFS的優先級
當然,CFS中還需要支持優先級。在新的體系中,優先級是以時間消耗(vruntime增長)的快慢來決定的。
就是說,對于CFS來說,衡量的時間累積的絕對值都是一樣紀錄在vruntime中的,但是不同優先級的進程時間增長的比率是不同的,高優先級進程時間增長的慢,低優先級時間增長的快。
比如,優先級為19的進程,實際占用cpu為1秒,那么在vruntime中就記錄1s。但是如果是-20優先級的進程,那么它很可能實際占CPU用10s,在vruntime中才會紀錄1s。
CFS真實實現的不同nice值的cpu消耗時間比例在內核中是按照“每差一級cpu占用時間差10%左右”這個原則來設定的。
這里的大概意思是說,如果有兩個nice值為0的進程同時占用cpu,那么它們應該每人占50%的cpu,如果將其中一個進程的nice值調整為1的話,那么此時應保證優先級高的進程比低的多占用10%的cpu,就是nice值為0的占55%,nice值為1的占45%。那么它們占用cpu時間的比例為55:45。
這個值的比例約為1.25。就是說,相鄰的兩個nice值之間的cpu占用時間比例的差別應該大約為1.25。根據這個原則,內核對40個nice值做了時間計算比例的對應關系,它在內核中以一個數組存在:
多CPU的CFS調度是怎樣的?
在上面的敘述中,我們可以認為系統中只有一個CPU,那么相關的調度隊列只有一個。
實際情況是系統是有多核甚至多個CPU的,CFS從一開始就考慮了這種情況,它對每個CPU核心都維護一個調度隊列,這樣每個CPU都對自己的隊列進程調度即可。
這也是CFS比O1調度算法更高效的根本原因:每個CPU一個隊列,就可以避免對全局隊列使用大內核鎖,從而提高了并行效率。
當然,這樣最直接的影響就是CPU之間的負載可能不均,為了維持CPU之間的負載均衡,CFS要定期對所有CPU進行load balance操作,于是就有可能發生進程在不同CPU的調度隊列上切換的行為。
這種操作的過程也需要對相關的CPU隊列進行鎖操作,從而降低了多個運行隊列帶來的并行性。
不過總的來說,CFS的并行隊列方式還是要比O1的全局隊列方式要高效。尤其是在CPU核心越來越多的情況下,全局鎖的效率下降顯著增加。
小編的目的是從Linux系統進程的優先級為出發點,我們也對CFS調度算法進行了比較深入的分析。在我的經驗來看,這些知識對我們在觀察系統的狀態和相關優化的時候都是非常有用的。
比如在使用top命令的時候,NI和PR值到底是什么意思?類似的地方還有ps命令中的NI和PRI值、ulimit命令-e和-r參數的區別等等。當然,希望看完本文后,能讓大家對這些命令顯示的了解更加深入。
除此之外,我們還會發現,雖然top命令中的PR值和ps -l命令中的PRI值的含義是一樣的,但是在優先級相同的情況下,它們顯示的值確不一樣。
關于Linux的進程優先級NI和PR有哪些區別呢就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。