CPU 是如何執(zhí)行任務(wù)的

學(xué)號(hào):17020110019? ? 姓名:高少魁

轉(zhuǎn)載自:https://mp.weixin.qq.com/s/dot49c2QGwA21kXlNsC4ng

【嵌牛導(dǎo)讀】介紹了CPU在進(jìn)行讀寫(xiě)數(shù)據(jù)時(shí)的調(diào)度方法以及一些緩存策略。

【嵌牛鼻子】CPU? ? 內(nèi)存? ? 任務(wù)調(diào)度? ? 讀寫(xiě)數(shù)據(jù)? ? 線程

【嵌牛正文】

本文大綱

先來(lái)認(rèn)識(shí) CPU 的架構(gòu)搀突,只有理解了 CPU 的架構(gòu)掠河,才能更好地理解 CPU 是如何讀寫(xiě)數(shù)據(jù)的融欧,對(duì)于現(xiàn)代 CPU 的架構(gòu)圖如下:

CPU架構(gòu)

可以看到,一個(gè) CPU 里通常會(huì)有多個(gè) CPU 核心惯吕,比如上圖中的 1 號(hào)和 2 號(hào) CPU 核心,并且每個(gè) CPU 核心都有自己的 L1 Cache 和 L2 Cache,而 L1 Cache 通常分為 dCache(數(shù)據(jù)緩存) 和 iCache(指令緩存)耘纱,L3 Cache 則是多個(gè)核心共享的,這就是 CPU 典型的緩存層次毕荐。

上面提到的都是 CPU 內(nèi)部的 Cache束析,放眼外部的話,還會(huì)有內(nèi)存和硬盤(pán)憎亚,這些存儲(chǔ)設(shè)備共同構(gòu)成了金字塔存儲(chǔ)層次员寇。如下圖所示:

從上圖也可以看到,從上往下虽填,存儲(chǔ)設(shè)備的容量會(huì)越大丁恭,而訪問(wèn)速度會(huì)越慢。至于每個(gè)存儲(chǔ)設(shè)備的訪問(wèn)延時(shí)斋日,你可以看下圖的表格:

你可以看到牲览, CPU 訪問(wèn) L1 Cache 速度比訪問(wèn)內(nèi)存快 100 倍,這就是為什么 CPU 里會(huì)有 L1~L3 Cache 的原因,目的就是把 Cache 作為 CPU 與內(nèi)存之間的緩存層第献,以減少對(duì)內(nèi)存的訪問(wèn)頻率贡必。

CPU 從內(nèi)存中讀取數(shù)據(jù)到 Cache 的時(shí)候,并不是一個(gè)字節(jié)一個(gè)字節(jié)讀取庸毫,而是一塊一塊的方式來(lái)讀取數(shù)據(jù)的仔拟,這一塊一塊的數(shù)據(jù)被稱(chēng)為 CPU Line(緩存行),所以CPU Line 是 CPU 從內(nèi)存讀取數(shù)據(jù)到 Cache 的單位飒赃。

至于 CPU Line 大小利花,在 Linux 系統(tǒng)可以用下面的方式查看到,你可以看我服務(wù)器的 L1 Cache Line 大小是 64 字節(jié)载佳,也就意味著?L1 Cache 一次載入數(shù)據(jù)的大小是 64 字節(jié)炒事。

對(duì)數(shù)組的加載,CPU 就會(huì)加載數(shù)組里面連續(xù)的多個(gè)數(shù)據(jù)到 Cache 里蔫慧,因此我們應(yīng)該按照物理內(nèi)存地址分布的順序去訪問(wèn)元素挠乳,這樣訪問(wèn)數(shù)組元素的時(shí)候,Cache 命中率就會(huì)很高姑躲,于是就能減少?gòu)膬?nèi)存讀取數(shù)據(jù)的頻率睡扬,從而可提高程序的性能。

但是黍析,在我們不使用數(shù)組卖怜,而是使用單獨(dú)的變量的時(shí)候,則會(huì)有 Cache 偽共享的問(wèn)題橄仍,Cache 偽共享問(wèn)題是一個(gè)性能殺手韧涨,我們應(yīng)該要規(guī)避它。

接下來(lái)侮繁,就來(lái)看看 Cache 偽共享是什么虑粥?又如何避免這個(gè)問(wèn)題?

現(xiàn)在假設(shè)有一個(gè)雙核心的 CPU宪哩,這兩個(gè) CPU 核心并行運(yùn)行著兩個(gè)不同的線程娩贷,它們同時(shí)從內(nèi)存中讀取兩個(gè)不同的數(shù)據(jù),分別是類(lèi)型為?long?的變量 A 和 B锁孟,這兩個(gè)數(shù)據(jù)的地址在物理內(nèi)存上是連續(xù)的彬祖,如果 Cahce Line 的大小是 64 字節(jié),并且變量 A 在 Cahce Line 的開(kāi)頭位置品抽,那么這兩個(gè)數(shù)據(jù)是位于同一個(gè) Cache Line 中储笑,又因?yàn)?CPU Line 是 CPU 從內(nèi)存讀取數(shù)據(jù)到 Cache 的單位,所以這兩個(gè)數(shù)據(jù)會(huì)被同時(shí)讀入到兩個(gè) CPU 核心的各自 Cache 中圆恤。

我們來(lái)思考一個(gè)問(wèn)題突倍,如果這兩個(gè)不同核心的線程分別修改不同的數(shù)據(jù),比如 1 號(hào) CPU 核心的線程只修改了變量 A,或 2 號(hào) CPU 核心的線程只修改了變量 B羽历,會(huì)發(fā)生什么呢焊虏?

分析偽共享的問(wèn)題

現(xiàn)在我們結(jié)合保證多核緩存一致的 MESI 協(xié)議,來(lái)說(shuō)明這一整個(gè)的過(guò)程秕磷。

①. 最開(kāi)始變量 A 和 B 都還不在 Cache 里面诵闭,假設(shè) 1 號(hào)核心綁定了線程 A,2 號(hào)核心綁定了線程 B澎嚣,線程 A 只會(huì)讀寫(xiě)變量 A疏尿,線程 B 只會(huì)讀寫(xiě)變量 B。

②. 1 號(hào)核心讀取變量 A币叹,由于 CPU 從內(nèi)存讀取數(shù)據(jù)到 Cache 的單位是 Cache Line润歉,也正好變量 A 和 變量 B 的數(shù)據(jù)歸屬于同一個(gè) Cache Line,所以 A 和 B 的數(shù)據(jù)都會(huì)被加載到 Cache颈抚,并將此 Cache Line 標(biāo)記為「獨(dú)占」?fàn)顟B(tài)。

③. ?接著嚼鹉,2 號(hào)核心開(kāi)始從內(nèi)存里讀取變量 B贩汉,同樣的也是讀取 Cache Line 大小的數(shù)據(jù)到 Cache 中,此 Cache Line 中的數(shù)據(jù)也包含了變量 A 和 變量 B锚赤,此時(shí) 1 號(hào)和 2 號(hào)核心的 Cache Line 狀態(tài)變?yōu)椤腹蚕怼範(fàn)顟B(tài)匹舞。

④. 1 號(hào)核心需要修改變量 A,發(fā)現(xiàn)此 Cache Line 的狀態(tài)是「共享」?fàn)顟B(tài)线脚,所以先需要通過(guò)總線發(fā)送消息給 2 號(hào)核心赐稽,通知 2 號(hào)核心把 Cache 中對(duì)應(yīng)的 Cache Line 標(biāo)記為「已失效」?fàn)顟B(tài),然后 1 號(hào)核心對(duì)應(yīng)的 Cache Line 狀態(tài)變成「已修改」?fàn)顟B(tài)浑侥,并且修改變量 A姊舵。

⑤. 之后,2 號(hào)核心需要修改變量 B寓落,此時(shí) 2 號(hào)核心的 Cache 中對(duì)應(yīng)的 Cache Line 是已失效狀態(tài)括丁,另外由于 1 號(hào)核心的 Cache 也有此相同的數(shù)據(jù),且狀態(tài)為「已修改」?fàn)顟B(tài)伶选,所以要先把 1 號(hào)核心的 Cache 對(duì)應(yīng)的 Cache Line 寫(xiě)回到內(nèi)存史飞,然后 2 號(hào)核心再?gòu)膬?nèi)存讀取 Cache Line 大小的數(shù)據(jù)到 Cache 中,最后把變量 B 修改到 2 號(hào)核心的 Cache 中仰税,并將狀態(tài)標(biāo)記為「已修改」?fàn)顟B(tài)构资。

所以,可以發(fā)現(xiàn)如果 1 號(hào)和 2 號(hào) CPU 核心這樣持續(xù)交替地分別修改變量 A 和 B陨簇,就會(huì)重復(fù) ④ 和 ⑤ 這兩個(gè)步驟吐绵,Cache 并沒(méi)有起到緩存的效果,雖然變量 A 和 B 之間其實(shí)并沒(méi)有任何的關(guān)系,但是因?yàn)橥瑫r(shí)歸屬于一個(gè) Cache Line 拦赠,這個(gè) Cache Line 中的任意數(shù)據(jù)被修改后巍沙,都會(huì)相互影響,從而出現(xiàn) ④ 和 ⑤ 這兩個(gè)步驟荷鼠。

因此句携,這種因?yàn)槎鄠€(gè)線程同時(shí)讀寫(xiě)同一個(gè) Cache Line 的不同變量時(shí),而導(dǎo)致 CPU Cache 失效的現(xiàn)象稱(chēng)為偽共享(False Sharing允乐。

避免偽共享的方法

因此矮嫉,對(duì)于多個(gè)線程共享的熱點(diǎn)數(shù)據(jù),即經(jīng)常會(huì)修改的數(shù)據(jù)牍疏,應(yīng)該避免這些數(shù)據(jù)剛好在同一個(gè) Cache Line 中蠢笋,否則就會(huì)出現(xiàn)偽共享的問(wèn)題。

接下來(lái)鳞陨,看看在實(shí)際項(xiàng)目中是用什么方式來(lái)避免偽共享的問(wèn)題的昨寞。

在 Linux 內(nèi)核中存在?__cacheline_aligned_in_smp?宏定義,是用于解決偽共享的問(wèn)題厦滤。

從上面的宏定義援岩,我們可以看到:

如果在多核(MP)系統(tǒng)里,該宏定義是?__cacheline_aligned掏导,也就是 Cache Line 的大邢砘场;

而如果在單核系統(tǒng)里趟咆,該宏定義是空的添瓷;

因此,針對(duì)在同一個(gè) Cache Line 中的共享的數(shù)據(jù)值纱,如果在多核之間競(jìng)爭(zhēng)比較嚴(yán)重鳞贷,為了防止偽共享現(xiàn)象的發(fā)生,可以采用上面的宏定義使得變量在 Cache Line 里是對(duì)齊的计雌。

舉個(gè)例子悄晃,有下面這個(gè)結(jié)構(gòu)體:

結(jié)構(gòu)體里的兩個(gè)成員變量 a 和 b 在物理內(nèi)存地址上是連續(xù)的,于是它們可能會(huì)位于同一個(gè) Cache Line 中凿滤,如下圖:

所以妈橄,為了防止前面提到的 Cache 偽共享問(wèn)題,我們可以使用上面介紹的宏定義翁脆,將 b 的地址設(shè)置為 Cache Line 對(duì)齊地址眷蚓,如下:

這樣 a 和 b 變量就不會(huì)在同一個(gè) Cache Line 中了,如下圖:

所以反番,避免 ?Cache 偽共享實(shí)際上是用空間換時(shí)間的思想沙热,浪費(fèi)一部分 Cache 空間叉钥,從而換來(lái)性能的提升。

我們?cè)賮?lái)看一個(gè)應(yīng)用層面的規(guī)避方案篙贸,有一個(gè) Java 并發(fā)框架 Disruptor 使用「字節(jié)填充 + 繼承」的方式投队,來(lái)避免偽共享的問(wèn)題。

Disruptor 中有一個(gè) RingBuffer 類(lèi)會(huì)經(jīng)常被多個(gè)線程使用爵川,代碼如下:

你可能會(huì)覺(jué)得 RingBufferPad 類(lèi)里 7 個(gè) long 類(lèi)型的名字很奇怪敷鸦,但事實(shí)上,它們雖然看起來(lái)毫無(wú)作用寝贡,但卻對(duì)性能的提升起到了至關(guān)重要的作用扒披。

我們都知道,CPU Cache 從內(nèi)存讀取數(shù)據(jù)的單位是 CPU Line圃泡,一般 64 位 CPU 的 CPU Line 的大小是 64 個(gè)字節(jié)碟案,一個(gè) long 類(lèi)型的數(shù)據(jù)是 8 個(gè)字節(jié),所以 CPU 一下會(huì)加載 8 個(gè) long 類(lèi)型的數(shù)據(jù)颇蜡。

根據(jù) JVM 對(duì)象繼承關(guān)系中父類(lèi)成員和子類(lèi)成員价说,內(nèi)存地址是連續(xù)排列布局的,因此 RingBufferPad 中的 7 個(gè) long 類(lèi)型數(shù)據(jù)作為 Cache Line?前置填充风秤,而 RingBuffer 中的 7 個(gè) long 類(lèi)型數(shù)據(jù)則作為 Cache Line?后置填充熔任,這 14 個(gè) long 變量沒(méi)有任何實(shí)際用途,更不會(huì)對(duì)它們進(jìn)行讀寫(xiě)操作唁情。

另外,RingBufferFelds 里面定義的這些變量都是?final?修飾的甫匹,意味著第一次加載之后不會(huì)再修改甸鸟,又由于「前后」各填充了 7 個(gè)不會(huì)被讀寫(xiě)的 long 類(lèi)型變量,所以無(wú)論怎么加載 Cache Line兵迅,這整個(gè) Cache Line 里都沒(méi)有會(huì)發(fā)生更新操作的數(shù)據(jù)抢韭,于是只要數(shù)據(jù)被頻繁地讀取訪問(wèn),就自然沒(méi)有數(shù)據(jù)被換出 Cache 的可能恍箭,也因此不會(huì)產(chǎn)生偽共享的問(wèn)題刻恭。

CPU 如何選擇線程的?

了解完 CPU 讀取數(shù)據(jù)的過(guò)程后扯夭,我們?cè)賮?lái)看看 CPU 是根據(jù)什么來(lái)選擇當(dāng)前要執(zhí)行的線程鳍贾。

在 Linux 內(nèi)核中,進(jìn)程和線程都是用?task_struct?結(jié)構(gòu)體表示的交洗,區(qū)別在于線程的 task_struct 結(jié)構(gòu)體里部分資源是共享了進(jìn)程已創(chuàng)建的資源骑科,比如內(nèi)存地址空間、代碼段构拳、文件描述符等咆爽,所以 Linux 中的線程也被稱(chēng)為輕量級(jí)進(jìn)程梁棠,因?yàn)榫€程的 task_struct 相比進(jìn)程的 task_struct 承載的資源比較少,因此以「輕」得名斗埂。

一般來(lái)說(shuō)符糊,沒(méi)有創(chuàng)建線程的進(jìn)程,是只有單個(gè)執(zhí)行流呛凶,它被稱(chēng)為是主線程男娄。如果想讓進(jìn)程處理更多的事情,可以創(chuàng)建多個(gè)線程分別去處理把兔,但不管怎么樣沪伙,它們對(duì)應(yīng)到內(nèi)核里都是?task_struct。

所以县好,Linux 內(nèi)核里的調(diào)度器围橡,調(diào)度的對(duì)象就是?task_struct,接下來(lái)我們就把這個(gè)數(shù)據(jù)結(jié)構(gòu)統(tǒng)稱(chēng)為任務(wù)缕贡。

在 Linux 系統(tǒng)中翁授,根據(jù)任務(wù)的優(yōu)先級(jí)以及響應(yīng)要求,主要分為兩種晾咪,其中優(yōu)先級(jí)的數(shù)值越小收擦,優(yōu)先級(jí)越高:

實(shí)時(shí)任務(wù),對(duì)系統(tǒng)的響應(yīng)時(shí)間要求很高谍倦,也就是要盡可能快地執(zhí)行實(shí)時(shí)任務(wù)塞赂,優(yōu)先級(jí)在?0~99?范圍內(nèi)的就算實(shí)時(shí)任務(wù);

普通任務(wù)昼蛀,響應(yīng)時(shí)間沒(méi)有很高的要求宴猾,優(yōu)先級(jí)在?100~139?范圍內(nèi)的都是普通任務(wù)級(jí)別;

調(diào)度類(lèi)

由于任務(wù)有優(yōu)先級(jí)之分叼旋,Linux 系統(tǒng)為了保障高優(yōu)先級(jí)的任務(wù)能夠盡可能早地被執(zhí)行仇哆,于是分為了這幾種調(diào)度類(lèi),如下圖:

Deadline 和 Realtime 這兩個(gè)調(diào)度類(lèi)夫植,都是應(yīng)用于實(shí)時(shí)任務(wù)的讹剔,這兩個(gè)調(diào)度類(lèi)的調(diào)度策略合起來(lái)共有這三種,它們的作用如下:

SCHED_DEADLINE:是按照 deadline 進(jìn)行調(diào)度的详民,距離當(dāng)前時(shí)間點(diǎn)最近的 deadline 的任務(wù)會(huì)被優(yōu)先調(diào)度延欠;

SCHED_FIFO:對(duì)于相同優(yōu)先級(jí)的任務(wù),按先來(lái)先服務(wù)的原則阐斜,但是優(yōu)先級(jí)更高的任務(wù)衫冻,可以搶占低優(yōu)先級(jí)的任務(wù),也就是優(yōu)先級(jí)高的可以「插隊(duì)」谒出;

SCHED_RR:對(duì)于相同優(yōu)先級(jí)的任務(wù)隅俘,輪流著運(yùn)行邻奠,每個(gè)任務(wù)都有一定的時(shí)間片,當(dāng)用完時(shí)間片的任務(wù)會(huì)被放到隊(duì)列尾部为居,以保證相同優(yōu)先級(jí)任務(wù)的公平性碌宴,但是高優(yōu)先級(jí)的任務(wù)依然可以搶占低優(yōu)先級(jí)的任務(wù);

而 Fair 調(diào)度類(lèi)是應(yīng)用于普通任務(wù)蒙畴,都是由 CFS 調(diào)度器管理的贰镣,分為兩種調(diào)度策略:

SCHED_NORMAL:普通任務(wù)使用的調(diào)度策略;

SCHED_BATCH:后臺(tái)任務(wù)的調(diào)度策略膳凝,不和終端進(jìn)行交互碑隆,因此在不影響其他需要交互的任務(wù),可以適當(dāng)降低它的優(yōu)先級(jí)蹬音。

完全公平調(diào)度

我們平日里遇到的基本都是普通任務(wù)上煤,對(duì)于普通任務(wù)來(lái)說(shuō),公平性最重要著淆,在 Linux 里面劫狠,實(shí)現(xiàn)了一個(gè)基于 CFS 的調(diào)度算法,也就是完全公平調(diào)度(Completely Fair Scheduling永部。

這個(gè)算法的理念是想讓分配給每個(gè)任務(wù)的 CPU 時(shí)間是一樣独泞,于是它為每個(gè)任務(wù)安排一個(gè)虛擬運(yùn)行時(shí)間 vruntime,如果一個(gè)任務(wù)在運(yùn)行苔埋,其運(yùn)行得越久懦砂,該任務(wù)的 vruntime 自然就會(huì)越大,而沒(méi)有被運(yùn)行的任務(wù)组橄,vruntime 是不會(huì)變化的孕惜。

那么,在 CFS 算法調(diào)度的時(shí)候晨炕,會(huì)優(yōu)先選擇 vruntime 少的任務(wù),以保證每個(gè)任務(wù)的公平性毫炉。

這就好比瓮栗,讓你把一桶的奶茶平均分到 10 杯奶茶杯里,你看著哪杯奶茶少瞄勾,就多倒一些费奸;哪個(gè)多了,就先不倒进陡,這樣經(jīng)過(guò)多輪操作愿阐,雖然不能保證每杯奶茶完全一樣多,但至少是公平的趾疚。

當(dāng)然缨历,上面提到的例子沒(méi)有考慮到優(yōu)先級(jí)的問(wèn)題以蕴,雖然是普通任務(wù),但是普通任務(wù)之間還是有優(yōu)先級(jí)區(qū)分的辛孵,所以在計(jì)算虛擬運(yùn)行時(shí)間 vruntime 還要考慮普通任務(wù)的權(quán)重值丛肮,注意權(quán)重值并不是優(yōu)先級(jí)的值,內(nèi)核中會(huì)有一個(gè) nice 級(jí)別與權(quán)重值的轉(zhuǎn)換表魄缚,nice 級(jí)別越低的權(quán)重值就越大宝与,至于 nice 值是什么,我們后面會(huì)提到冶匹。于是就有了以下這個(gè)公式:

你可以不用管 NICE_0_LOAD 是什么习劫,你就認(rèn)為它是一個(gè)常量,那么在「同樣的實(shí)際運(yùn)行時(shí)間」里嚼隘,高權(quán)重任務(wù)的 vruntime 比低權(quán)重任務(wù)的 vruntime?诽里,你可能會(huì)奇怪為什么是少的?你還記得 CFS 調(diào)度嗎嗓蘑,它是會(huì)優(yōu)先選擇 vruntime 少的任務(wù)進(jìn)行調(diào)度须肆,所以高權(quán)重的任務(wù)就會(huì)被優(yōu)先調(diào)度了,于是高權(quán)重的獲得的實(shí)際運(yùn)行時(shí)間自然就多了桩皿。

CPU 運(yùn)行隊(duì)列

一個(gè)系統(tǒng)通常都會(huì)運(yùn)行著很多任務(wù)豌汇,多任務(wù)的數(shù)量基本都是遠(yuǎn)超 CPU 核心數(shù)量,因此這時(shí)候就需要排隊(duì)泄隔。

事實(shí)上拒贱,每個(gè) CPU 都有自己的運(yùn)行隊(duì)列(Run Queue, rq,用于描述在此 CPU 上所運(yùn)行的所有進(jìn)程佛嬉,其隊(duì)列包含三個(gè)運(yùn)行隊(duì)列逻澳,Deadline 運(yùn)行隊(duì)列 dl_rq、實(shí)時(shí)任務(wù)運(yùn)行隊(duì)列 rt_rq 和 CFS 運(yùn)行隊(duì)列 csf_rq暖呕,其中 csf_rq 是用紅黑樹(shù)來(lái)描述的斜做,按 vruntime 大小來(lái)排序的,最左側(cè)的葉子節(jié)點(diǎn)湾揽,就是下次會(huì)被調(diào)度的任務(wù)瓤逼。

這幾種調(diào)度類(lèi)是有優(yōu)先級(jí)的,優(yōu)先級(jí)如下:Deadline > Realtime > Fair库物,這意味著 Linux 選擇下一個(gè)任務(wù)執(zhí)行的時(shí)候霸旗,會(huì)按照此優(yōu)先級(jí)順序進(jìn)行選擇,也就是說(shuō)先從?dl_rq?里選擇任務(wù)戚揭,然后從?rt_rq?里選擇任務(wù)诱告,最后從?csf_rq?里選擇任務(wù)。因此民晒,實(shí)時(shí)任務(wù)總是會(huì)比普通任務(wù)優(yōu)先被執(zhí)行精居。

調(diào)整優(yōu)先級(jí)

如果我們啟動(dòng)任務(wù)的時(shí)候锄禽,沒(méi)有特意去指定優(yōu)先級(jí)的話,默認(rèn)情況下都是普通任務(wù)箱蟆,普通任務(wù)的調(diào)度類(lèi)是 Fail沟绪,由 CFS 調(diào)度器來(lái)進(jìn)行管理。CFS 調(diào)度器的目的是實(shí)現(xiàn)任務(wù)運(yùn)行的公平性空猜,也就是保障每個(gè)任務(wù)的運(yùn)行時(shí)間是差不多的绽慈。

如果你想讓某個(gè)普通任務(wù)有更多的執(zhí)行時(shí)間,可以調(diào)整任務(wù)的?nice?值辈毯,從而讓優(yōu)先級(jí)高一些的任務(wù)執(zhí)行更多時(shí)間坝疼。nice 的值能設(shè)置的范圍是?-20~19, 值越低谆沃,表明優(yōu)先級(jí)越高钝凶,因此 -20 是最高優(yōu)先級(jí),19 則是最低優(yōu)先級(jí)唁影,默認(rèn)優(yōu)先級(jí)是 0耕陷。

是不是覺(jué)得 nice 值的范圍很詭異?事實(shí)上据沈,nice 值并不是表示優(yōu)先級(jí)哟沫,而是表示優(yōu)先級(jí)的修正數(shù)值,它與優(yōu)先級(jí)(priority)的關(guān)系是這樣的:priority(new) = priority(old) + nice锌介。內(nèi)核中嗜诀,priority 的范圍是 0~139,值越低孔祸,優(yōu)先級(jí)越高隆敢,其中前面的 0~99 范圍是提供給實(shí)時(shí)任務(wù)使用的,而 nice 值是映射到 100~139崔慧,這個(gè)范圍是提供給普通任務(wù)用的拂蝎,因此 nice 值調(diào)整的是普通任務(wù)的優(yōu)先級(jí)。

在前面我們提到了惶室,權(quán)重值與 nice 值的關(guān)系匣屡,nice 值越低,權(quán)重值就越大拇涤,計(jì)算出來(lái)的 vruntime 就會(huì)越少,由于 CFS 算法調(diào)度的時(shí)候誉结,就會(huì)優(yōu)先選擇 vruntime 少的任務(wù)進(jìn)行執(zhí)行鹅士,所以 nice 值越低,任務(wù)的優(yōu)先級(jí)就越高惩坑。

我們?cè)趩?dòng)任務(wù)的時(shí)候掉盅,可以指定 nice 的值也拜,比如將 mysqld 以 -3 優(yōu)先級(jí):

如果想修改已經(jīng)運(yùn)行中的任務(wù)的優(yōu)先級(jí),則可以使用?renice?來(lái)調(diào)整 nice 值:

nice 調(diào)整的是普通任務(wù)的優(yōu)先級(jí)趾痘,所以不管怎么縮小 nice 值慢哈,任務(wù)永遠(yuǎn)都是普通任務(wù),如果某些任務(wù)要求實(shí)時(shí)性比較高永票,那么你可以考慮改變?nèi)蝿?wù)的優(yōu)先級(jí)以及調(diào)度策略卵贱,使得它變成實(shí)時(shí)任務(wù),比如:

總結(jié)

理解 CPU 是如何讀寫(xiě)數(shù)據(jù)的前提侣集,是要理解 CPU 的架構(gòu)键俱,CPU 內(nèi)部的多個(gè) Cache + 外部的內(nèi)存和磁盤(pán)構(gòu)成了金字塔的存儲(chǔ)器結(jié)構(gòu),在這個(gè)金字塔中世分,越往下编振,存儲(chǔ)器的容量就越大,但訪問(wèn)速度就會(huì)小臭埋。

CPU 讀寫(xiě)數(shù)據(jù)的時(shí)候踪央,并不是按一個(gè)一個(gè)字節(jié)為單位來(lái)進(jìn)行讀寫(xiě),而是以 CPU Line 大小為單位瓢阴,CPU Line 大小一般是 64 個(gè)字節(jié)畅蹂,也就意味著 CPU 讀寫(xiě)數(shù)據(jù)的時(shí)候,每一次都是以 64 字節(jié)大小為一塊進(jìn)行操作炫掐。

因此魁莉,如果我們操作的數(shù)據(jù)是數(shù)組,那么訪問(wèn)數(shù)組元素的時(shí)候募胃,按內(nèi)存分布的地址順序進(jìn)行訪問(wèn)旗唁,這樣能充分利用到 Cache,程序的性能得到提升痹束。但如果操作的數(shù)據(jù)不是數(shù)組检疫,而是普通的變量,并在多核 CPU 的情況下祷嘶,我們還需要避免 Cache Line 偽共享的問(wèn)題屎媳。

所謂的 Cache Line 偽共享問(wèn)題就是,多個(gè)線程同時(shí)讀寫(xiě)同一個(gè) Cache Line 的不同變量時(shí)论巍,而導(dǎo)致 CPU Cache 失效的現(xiàn)象烛谊。那么對(duì)于多個(gè)線程共享的熱點(diǎn)數(shù)據(jù),即經(jīng)常會(huì)修改的數(shù)據(jù)嘉汰,應(yīng)該避免這些數(shù)據(jù)剛好在同一個(gè) Cache Line 中丹禀,避免的方式一般有 Cache Line 大小字節(jié)對(duì)齊,以及字節(jié)填充等方法。

系統(tǒng)中需要運(yùn)行的多線程數(shù)一般都會(huì)大于 CPU 核心双泪,這樣就會(huì)導(dǎo)致線程排隊(duì)等待 CPU持搜,這可能會(huì)產(chǎn)生一定的延時(shí),如果我們的任務(wù)對(duì)延時(shí)容忍度很低焙矛,則可以通過(guò)一些人為手段干預(yù) Linux 的默認(rèn)調(diào)度策略和優(yōu)先級(jí)葫盼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市村斟,隨后出現(xiàn)的幾起案子贫导,更是在濱河造成了極大的恐慌,老刑警劉巖邓梅,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脱盲,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡日缨,警方通過(guò)查閱死者的電腦和手機(jī)钱反,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)匣距,“玉大人面哥,你說(shuō)我怎么就攤上這事∫愦” “怎么了尚卫?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)尸红。 經(jīng)常有香客問(wèn)我吱涉,道長(zhǎng),這世上最難降的妖魔是什么外里? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任怎爵,我火速辦了婚禮,結(jié)果婚禮上盅蝗,老公的妹妹穿的比我還像新娘鳖链。我一直安慰自己,他們只是感情好墩莫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布芙委。 她就那樣靜靜地躺著,像睡著了一般狂秦。 火紅的嫁衣襯著肌膚如雪灌侣。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,718評(píng)論 1 305
  • 那天裂问,我揣著相機(jī)與錄音侧啼,去河邊找鬼玖姑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛慨菱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播戴甩,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼符喝,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了甜孤?” 一聲冷哼從身側(cè)響起协饲,我...
    開(kāi)封第一講書(shū)人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎缴川,沒(méi)想到半個(gè)月后茉稠,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡把夸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年而线,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恋日。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡膀篮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出岂膳,到底是詐尸還是另有隱情誓竿,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布谈截,位于F島的核電站筷屡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏簸喂。R本人自食惡果不足惜毙死,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望娘赴。 院中可真熱鬧规哲,春花似錦、人聲如沸诽表。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)竿奏。三九已至袄简,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間泛啸,已是汗流浹背绿语。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吕粹。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓种柑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親匹耕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子聚请,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容