用c语言实现对n个进程采用“短进程优先”算法的进程调度_为什么Linux CFS调度器没有带来惊艳的碾压效果?...
文章轉(zhuǎn)自公眾號“人人都是極客”
但凡懂Linux內(nèi)核的,都知道Linux內(nèi)核的CFS進程調(diào)度算法,無論是從2.6.23將其初引入時的論文,還是各類源碼分析,文章,以及Linux內(nèi)核專門的圖書,都給人這樣一種感覺,即?CFS調(diào)度器是革命性的,它將徹底改變進程調(diào)度算法。?預(yù)期中,人們期待它會帶來令人驚艷的效果。然而這是錯覺。人們希望CFS速勝,但是分析來分析去,卻只是在某些方面比O(1)調(diào)度器稍微好一點點。甚至在某些方面比不上古老的4.4BSD調(diào)度器。可是人們卻依然對其趨之若鶩,特別是源碼分析,汗牛塞屋!為什么CFS對別的調(diào)度算法沒有帶來碾壓的效果呢?首先,在真實世界,碾壓是不存在的,人與人,事與事既然被放在了同一個重量級梯隊比較,其之間的差別沒有想象的那么大,根本就不在誰碾壓誰。不能被小說電視劇電影蒙蔽了,此外,徐曉冬大擺拳暴打雷雷也不算數(shù),因為他們本就不是一個梯隊。任何領(lǐng)域,革命性的碾壓式推陳出新并不是沒有,但是概率極低,人們普遍的狂妄在于,總是認(rèn)為自己所置身的環(huán)境正在發(fā)生著某種碾壓式的變革,但其實,最終大概率不過是一場平庸。
最終就出現(xiàn)了角力,僵持。其次,我們應(yīng)該看到,CFS調(diào)度器聲稱它會給交互式進程帶來福音,在這方面CFS確實比O(1)做得好,但是驚艷的效果來自于粉絲的認(rèn)同。Linux系統(tǒng)交互進程本來就不多,Linux更多地被裝在服務(wù)器,而在服務(wù)器看來,吞吐是要比交互響應(yīng)更加重要的。那么以交互為主的Android系統(tǒng)呢?我們知道,Android也是采用了CFS調(diào)度器,也有一些是BFS,為什么同樣沒有帶來驚艷的效果呢?我承認(rèn),2008年前后出現(xiàn)CFS時還沒有Android,等到Android出現(xiàn)時,其采用的Linux內(nèi)核已經(jīng)默認(rèn)了CFS調(diào)度器,我們看下Android版本,Linux內(nèi)核版本以及發(fā)行時間的關(guān)系:Linux內(nèi)核在2.6.23就采用了CFS調(diào)度器。所以一個原因就是沒有比較。Android系統(tǒng)上,CFS沒有機會和O(1)做比較。另外,即便回移一個O(1)調(diào)度器到Android系統(tǒng)去和CFS做AB,在我看來,CFS同樣不會驚艷,原因很簡單,Android系統(tǒng)幾乎都是交互進程,前臺進程卻永遠(yuǎn)只有一個,你幾乎感受不到進程的切換卡頓,換句話說,即便CFS對待交互式進程比O(1)好太多,你也感受不到,因為對于手機,平板而言,你切換APP的時間遠(yuǎn)遠(yuǎn)大于進程切換的時間粒度。那么,CFS到底好在哪里?簡單點說,CFS的意義在于,?在一個混雜著大量計算型進程和IO交互進程的系統(tǒng)中,CFS調(diào)度器對待IO交互進程要比O(1)調(diào)度器更加友善和公平。理解這一點至關(guān)重要。其實,CFS調(diào)度器的理念非常古老,就說在業(yè)界,CFS的思想早就被應(yīng)用在了磁盤IO調(diào)度,數(shù)據(jù)包調(diào)度等領(lǐng)域,甚至最最古老的SRV3以及4.3BSD UNIX系統(tǒng)的進程調(diào)度中早就有了CFS的身影,可以說,Linux只是使用CFS調(diào)度器,而不是設(shè)計了CFS調(diào)度器!就以4.3BSD調(diào)度器為例,我們看一下其調(diào)度原理。4.3BSD采用了1秒搶占制,每間隔1秒,會對整個系統(tǒng)進程進行優(yōu)先級排序,然后找到優(yōu)先級最高的投入運行,非常簡單的一個思想,現(xiàn)在看看它是如何計算優(yōu)先級的。首先,每一個進程j均擁有一個CPU滴答的度量值Cj,每一個時鐘滴答,當(dāng)前在運行的進程的CPU度量值C會遞增:當(dāng)一個1秒的時間區(qū)間i過去之后,Cj被重置,該進程j的優(yōu)先級采用下面的公式計算:
可以計算,在一個足夠長的時間段內(nèi),兩個進程運行的總時間比例,將和它們的Base_PrioBase_Prio優(yōu)先級的比例相等。4.3BSD的優(yōu)先級公平調(diào)度是CPU滴答驅(qū)動的。現(xiàn)在看Linux的CFS,CFS采用隨時搶占制。每一個進程j均攜帶一個?虛擬時鐘VCj,每一個時鐘滴答,當(dāng)前進程k的VCk會重新計算,同時調(diào)度器選擇VC最小的進程運行,計算方法非常簡單:可見, Linux的CFS簡直就是4.3BSD進程調(diào)度的自驅(qū)無級變速版本!如果你想了解CFS的精髓,上面的就是了。換成語言描述,CFS的精髓就是 “n個進程的系統(tǒng),任意長的時間周期T,每一個進程運行T/n的時間!”當(dāng)然,在現(xiàn)實和實現(xiàn)中,會有80%的代碼處理20%的剩余問題,比如如何獎勵睡眠太久的進程等等,但是這些都不是精髓。綜上,我們總結(jié)了:現(xiàn)實世界很難碾壓同級別的人或事。
大量的Linux服務(wù)器不需要照顧交互進程,CFS優(yōu)勢無法凸顯。
大量的Android系統(tǒng)沒有和O(1)同臺競技的機會。
大量的Android系統(tǒng)交互進程很難感知進程調(diào)度這件事。
CFS調(diào)度思想古已有之。
也就是說,給定一個進程優(yōu)先級,就會計算出一個時間片與之對應(yīng),我們忽略獎懲相關(guān)的動態(tài)優(yōu)先級,看一下原始O(1)算法中一個進程時間片的計算:
#define?BASE_TIMESLICE(p)?(MIN_TIMESLICE?+?/
((MAX_TIMESLICE?-?MIN_TIMESLICE)?*?/
(MAX_PRIO-1?-?(p)->static_prio)?/?(MAX_USER_PRIO-1)))static?inline?unsigned?int?task_timeslice(task_t?*p){return?BASE_TIMESLICE(p);
}
針對上述問題,2.6內(nèi)核的O(1)引入了雙斜率來解決:
static?unsigned?int?task_timeslice(task_t?*p){if?(p->static_prio?0))return?SCALE_PRIO(DEF_TIMESLICE*4,?p->static_prio);elsereturn?SCALE_PRIO(DEF_TIMESLICE,?p->static_prio);
}
直觀圖示如下:
貌似問題解決了,但是如果單單揪住上圖的某一個優(yōu)先級子區(qū)間來看,還是會有問題,這就是相對優(yōu)先級的問題。我們看到,高優(yōu)先級的時間片是緩慢增減的,而低優(yōu)先級的時間片卻是陡然增減,同樣都是相差同樣優(yōu)先級的進程,其優(yōu)先級分布影響了它們的時間片分配。本來是治瘸子,結(jié)果腿好了,但是胳臂壞了。本質(zhì)上來講,這都源自于下面兩個原因:固定的優(yōu)先級映射到固定的時間片。相對優(yōu)先級和絕對優(yōu)先級混雜。那么這個問題如何解決?優(yōu)先級和時間片本來就是兩個概念,二者中間還得有個變量溝通才可以。優(yōu)先級高只是說明該進程能運行的久一些,但是到底久多少,并不是僅僅優(yōu)先級就能決定的,還要綜合考慮,換句話距離來說,如果只有一個進程,那么即便它優(yōu)先級再低,它也可以永久運行,如果系統(tǒng)中有很多的進程,即便再高優(yōu)先級的進程也要讓出一些時間給其它進程。所以,考慮到系統(tǒng)中總體的進程情況,將優(yōu)先級轉(zhuǎn)換為權(quán)重,將時間片轉(zhuǎn)換為份額,CFS就是了。最終的坐標(biāo)系應(yīng)該是權(quán)重占比/時間片坐標(biāo)系而不是權(quán)重(或者優(yōu)先級)/時間片。應(yīng)該是這個平滑的樣子:看來,Linux CFS只是為了解決O(1)中一個“靜態(tài)優(yōu)先級/時間片映射”問題的,那么可想而知,它又能帶來什么驚艷效果呢?這里還有個“但是”,這個O(1)調(diào)度器的問題其實在計算密集型的守護進程看來,并不是問題,反而是好事,畢竟高優(yōu)先級進程可以無條件持續(xù)運行很久而不切換。這對于吞吐率的提高,cache利用都是有好處的。無非也就侵?jǐn)_了交互進程唄,又有何妨。當(dāng)然,使用調(diào)優(yōu)CFS的時候,難免也要遇到IO睡眠獎懲等剩余的事情去設(shè)計一些trick算法,這破費精力。對了,還要設(shè)置你的內(nèi)核為HZ1000哦,這樣更能體現(xiàn)CFS的平滑性,就像它宣稱的那樣。我難以想象,除了Ubuntu,Suse等花哨的桌面發(fā)行版之外,還有哪個Linux需要打開HZ1000,服務(wù)器用HZ250不挺好嗎?關(guān)于調(diào)度的話題基本就說完了,但是在進入下一步固有的噴子環(huán)節(jié)之前,還有兩點要強調(diào):CFS的時間片是動態(tài)的,是系統(tǒng)負(fù)載均衡以及其優(yōu)先級的函數(shù),這便可以把進程調(diào)度動態(tài)適應(yīng)到系統(tǒng)最佳,以節(jié)省切換開銷。
即便是到了多核時代,對于實時進程依然像單核時代那般嚴(yán)格遵循最優(yōu)先調(diào)度。
我還是想說,在調(diào)度器設(shè)計方面,大部分的人們關(guān)注點錯了!
在CPU核數(shù)越來越多的時代,人們更應(yīng)該關(guān)心把進程調(diào)度到哪里CPU核上而不是某個CPU核要運行哪個進程。
單核時代一路走過來的Linux,發(fā)展迅猛,這無可厚非,但是成就一個操作系統(tǒng)內(nèi)核的并不單單是技術(shù),還有別的。這些當(dāng)然程序員們很不愛聽,程序員最煩非技術(shù)方面的東西了,程序員跟誰都比寫代碼,程序員特別喜歡噴領(lǐng)導(dǎo)不會寫代碼云云。Linux在純技術(shù)方面并不優(yōu)秀,Linux總體上優(yōu)秀的原因是因為有一群非代碼不明志的程序員在讓它變得越來越優(yōu)秀,另一方面還要歸功于開源和社區(qū)。Linux的學(xué)習(xí)門檻極低,如果一個公司能不費吹灰之力招聘到一個Linux程序員的話,那它干嘛還要費勁九牛二虎之力去招聘什么高端的BSD程序員呢?最終的結(jié)果就是,Linux用的人極多,想換也換不掉了。但無論如何也沒法彌補Linux內(nèi)核上的一些原則性錯誤。Linux內(nèi)核還是以原始的主線為base,以講Linux內(nèi)核的書為例,經(jīng)典的Robert Love的《Linux內(nèi)核設(shè)計與實現(xiàn)》,以及《深入理解Linux內(nèi)核》,在講進程調(diào)度的時候,關(guān)于多核負(fù)載均衡的筆墨都是少之又少甚至沒有,如此經(jīng)典的著作把很多同行引向了那萬劫不復(fù)的代碼深淵。于是乎,鋪天蓋地的CFS源碼分析紛至沓來。但其實,拋開這么一個再普通不過的Linux內(nèi)核,現(xiàn)代操作系統(tǒng)進入了多核時代,其核心正是在cache利用上的革新,帶來的轉(zhuǎn)變就是進程調(diào)度和內(nèi)存管理的革新。review一下Linux內(nèi)核源碼,這些改變早就已經(jīng)表現(xiàn)了出來。可悲的是,關(guān)于Linux內(nèi)核的經(jīng)典書籍卻再也沒有更新,所有的從傳統(tǒng)學(xué)校出來的喜歡看書學(xué)習(xí)的,依然是抱著10年前的大部頭在啃。當(dāng)然了,Linux內(nèi)核作為一個代碼來講,它是普適的,所以社區(qū)很難看到且關(guān)注單單是多核的問題,社區(qū)關(guān)注的最多的是可維護性,而不是性能。Linux新特性在128MB內(nèi)存的i386機器上跑沒有問題,那就是OK的。只要不是80%以上的人遭遇的新問題,社區(qū)是從不care的,同時,正因為如此,社區(qū)還會引入bug,這也是令人想嘆息都不能嘆息。我的看法吧,社區(qū)只是一個一切以代碼為準(zhǔn)繩的程序員社區(qū),社區(qū)不會過于關(guān)注體系結(jié)構(gòu)的發(fā)展和新特性,這些都是廠商的事情。回到進程調(diào)度的話題,正因為Linux一直在關(guān)注調(diào)度算法本身以及其實現(xiàn)的代碼,才會出現(xiàn)The Linux Scheduler: a Decade of Wasted Cores,這篇十分中肯的paper:http://www.ece.ubc.ca/~sasha/papers/eurosys16-final29.pdf同樣,我一向噴的TCP也是如此,人們關(guān)注TCP的實現(xiàn)代碼本身,才會讓它越來越復(fù)雜,然后越來越脆弱,也許你會說這就是進化,但是趁著萬劫不復(fù)前,不是還有回爐的機會嗎?還沒有進化到必須繼續(xù)進化的地步吧。如果站在外面看且具有強制措施,估計早就沒有垃圾TCP了吧。浙江溫州皮鞋濕,下雨進水不會胖。總結(jié)
以上是生活随笔為你收集整理的用c语言实现对n个进程采用“短进程优先”算法的进程调度_为什么Linux CFS调度器没有带来惊艳的碾压效果?...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c语言定时器_分享10个值得关注的C语言
- 下一篇: 删除同域名所有cookies_淘宝自动登