CPU有很多硬件提升手段,其中較為常見的是超標(biāo)量(superscalar)、流水線(pipelining)、超線程(Hyper-Threading)、多核(multi-core)、SIMD等,通常較難理解,本文以洗衣服為例嘗試通俗理解這些概念.
假如把一個(gè)線程任務(wù)模擬成洗衣機(jī)器操作,那一個(gè)線程包含多個(gè)指令(處理上衣、處理褲子、處理襪子.....),一個(gè)指令又包含多個(gè)周期(取衣服、洗衣服、晾衣服......);CPU 就是那洗衣工廠,工廠里有取衣機(jī)器 A、洗衣機(jī)器 B、晾衣機(jī)器 C 、燙衣機(jī)器 D、衣服放回機(jī)器 E,一開始流程如下:
1.機(jī)器A取上衣--機(jī)器B洗上衣--機(jī)器C晾上衣--機(jī)器D燙上衣--機(jī)器E放回上衣
2.機(jī)器A取褲子--機(jī)器B洗褲子--機(jī)器C晾褲子--機(jī)器D燙褲子--機(jī)器E放回褲子
3.機(jī)器A取襪子--機(jī)器B洗襪子--機(jī)器C晾襪子--機(jī)器D燙襪子--機(jī)器E放回襪子
4.機(jī)器A取鞋子--機(jī)器B洗鞋子--機(jī)器C晾鞋子--機(jī)器D燙鞋子--機(jī)器E放回鞋子
5...
最開始 CPU 就是順序執(zhí)行如上1-2-3-.....步驟的,現(xiàn)在有好幾筐(衣服、褲子、鞋子......)要洗,如何提升速度?
超標(biāo)量(superscalar)
最開始樸素想法就是工廠內(nèi)多買機(jī)器,譬如取上衣機(jī)器買 2 臺(tái),洗衣機(jī)器買 2 臺(tái)..........
洗衣工廠就變成
1.機(jī)器A1取上衣--機(jī)器B1洗上衣--機(jī)器C1晾上衣--機(jī)器D1燙上衣--機(jī)器E1放回上衣
機(jī)器A2取褲子--機(jī)器B2洗褲子--機(jī)器C2晾褲子--機(jī)器D2燙褲子--機(jī)器E2放回褲子
2.機(jī)器A1取襪子--機(jī)器B1洗襪子--機(jī)器C1晾襪子--機(jī)器D1燙襪子--機(jī)器E1放回襪子
機(jī)器A2取鞋子--機(jī)器B2洗鞋子--機(jī)器C2晾鞋子--機(jī)器D2燙鞋子--機(jī)器E2放回鞋子
3.....
這樣時(shí)間就能減半了
流水線(pipelining)
仔細(xì)看從取衣到放回一個(gè)流程里雖然每個(gè)機(jī)器都用到了,但任何一個(gè)時(shí)刻都只有一個(gè)機(jī)器在工作.
譬如:機(jī)器 A1/A2取完衣服后就空閑者一直到E1/E2放回衣服才繼續(xù)工作,大部分時(shí)候都空閑著。
流水線就是不讓任何一個(gè)機(jī)器空閑,沒必要一個(gè)指令周期走完,可以繼續(xù)執(zhí)行其他指令。
T1 時(shí)刻:機(jī)器A1取上衣
T2 時(shí)刻:機(jī)器B1洗上衣+機(jī)器A1取褲子
T3 時(shí)刻:機(jī)器C1晾上衣+機(jī)器B1洗褲子+機(jī)器 A1 取襪子
T4 時(shí)刻:機(jī)器D1燙上衣+機(jī)器C1晾褲子+機(jī)器 B1 洗襪子+機(jī)器 A1 取鞋子
........
縱向看仍然是一個(gè)指令的完整周期(取衣服、洗衣服、晾衣服.....), 橫向看會(huì)發(fā)現(xiàn) A1 一直在工作被利用起來了,只要一直運(yùn)行時(shí)間會(huì)發(fā)現(xiàn) A1 ~ E1 各個(gè)機(jī)器都會(huì)被利用起來持續(xù)工作。
超線程(Hyper-Threading)
超標(biāo)量(superscalar)和流水線(pipelining)都是線程里的優(yōu)化方案,能讓單線程程序跑的更快,而超線程(Hyper-Threading)就是不同線程間的優(yōu)化方案了。
因?yàn)橛械木€程涉及和外部的數(shù)據(jù)交換,譬如需要等數(shù)據(jù)從內(nèi)存乃至更慢的網(wǎng)絡(luò)、磁盤裝載到 L1、L2 chache,這時(shí)候可以讓 CPU處理另一個(gè)線程。
繼續(xù)類比就類似于洗衣工廠發(fā)現(xiàn)某籮筐 A 里的衣服較臟需要等洗衣液送過來才能繼續(xù)洗,那可以保存籮筐A 的進(jìn)度轉(zhuǎn)而洗那些較干凈無需等外部的某籮筐B(yǎng)里的衣服,等外部的洗衣液送過來后再處理籮筐A 里的衣服。
所以越是 IO 密集型應(yīng)用,超線程效果就越大,譬如DBA 一般建議MySQL 的thread_running參數(shù)設(shè)置為 cpu 核數(shù)*2,這就是把超線程當(dāng)成真正的核來用了。
超線程對(duì) CPU 密集型應(yīng)用就無用了,CPU 核數(shù)是多少就只能開多少任務(wù)。
日常應(yīng)用來說超線程能提升 30%的吞吐量, 而這 30%的提升只是增加了 5%的額外電路,看起來性價(jià)比很高;但開啟多線程會(huì)犧牲單線程的性能,而且現(xiàn)在大部人日常應(yīng)用根本用不滿CPU的那么多核和線程,所有有些 CPU(如MacBook的 M 系列 CPU)就沒有超線程技術(shù)。
多核(multi-core)
多核(multi-core)很容易理解了,還是以洗衣服為例幾個(gè)核就是額外再建幾個(gè)洗衣工廠,當(dāng)然成本也是跟著翻幾倍。
SIMD
上面的例子都是假設(shè)機(jī)器一次只能處理一件任務(wù),那能不能改造下機(jī)器(譬如增加機(jī)械臂)讓機(jī)器 A 一次取 10 件而不是 1 件衣服,讓機(jī)器 B 一次洗 10 個(gè)鞋子而不是 1 個(gè)?
SIMD就是類似思路,事實(shí)上這就是 SIMD 被叫做單指令流多數(shù)據(jù)流的原因,一次處理大量類似的數(shù)據(jù),譬如多媒體數(shù)據(jù)、數(shù)據(jù)分析/AI領(lǐng)域 的矩陣數(shù)據(jù)。
譬如Python的Numpy庫就是用了SIMD指令集 AVX 系列(AVX、AVX2乃至AVX512)來處理數(shù)據(jù),所以哪怕沒用GPU速度也很快。