自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

哪個程序經(jīng)得起這樣的優(yōu)化?

開發(fā) 項目管理
性能優(yōu)化指在不影響系統(tǒng)運行正確性的前提下,使之運行得更快,完成特定功能所需的時間更短,或擁有更強大的服務(wù)能力。

[[355615]]

本文轉(zhuǎn)載自微信公眾號「碼磚雜役」,作者我不想種地 。轉(zhuǎn)載本文請聯(lián)系碼磚雜役公眾號。  

#  一、思維導(dǎo)圖

# 二、什么是性能優(yōu)化?

性能優(yōu)化指在不影響系統(tǒng)運行正確性的前提下,使之運行得更快,完成特定功能所需的時間更短,或擁有更強大的服務(wù)能力。

## 關(guān)注

不同程序有不同的性能關(guān)注點,比如科學(xué)計算關(guān)注運算速度,比如游戲引擎注重渲染效率,而服務(wù)程序追求吞吐能力。

服務(wù)器一般都是可水平擴展的分布式系統(tǒng),系統(tǒng)處理能力取決于單機負(fù)載能力和水平擴展能力,所以,提升單機性能和提升水平擴展能力是兩個主要方向,理論上系統(tǒng)水平方向可以無限擴展,但水平擴展后往往面臨通信成本飆高(甚至瓶頸),單機處理能力下降的問題。

## 指標(biāo)

衡量單機性能有很多指標(biāo),比如:QPS(Query Per Second)、TPS、OPS、IOPS、最大連接數(shù)、并發(fā)數(shù)等評估吞吐的指標(biāo)。

CPU為了提高吞吐,會把指令執(zhí)行分為多個階段,會搞指令Pipeline,同樣,軟件系統(tǒng)為了提升處理能力,往往會引入批處理(攢包)等,但跟CPU流水線會引起Latency增加一樣,伴隨著系統(tǒng)負(fù)載增加也會導(dǎo)致延遲(Latency)增加,可見,系統(tǒng)吞吐和延遲是兩個沖突的目標(biāo)。

顯然,過高的延遲是不能接受的,所以,服務(wù)器性能優(yōu)化的目標(biāo)往往變成:追求可容忍延遲(Latency)下的最大吞吐(Throughput)。

延遲(也叫響應(yīng)時間:RT)不是固定的,通常在一個范圍內(nèi)波動,我們可以用平均時延去評估系統(tǒng)性能,但有時候,平均時延是不夠的,這很容易理解,比如80%的請求都在10毫秒以內(nèi)得到響應(yīng),但20%的請求時延超過2秒,而這20%的高延遲可能會引發(fā)投訴,同樣不可接受。

一個改進(jìn)措施是使用TP90、TP99之類的指標(biāo),它不是取平均,而是需確保排序后90%、99%請求滿足時延的要求。

通常,執(zhí)行效率(CPU)是我們的重點關(guān)注,但有時候,我們也需要關(guān)注內(nèi)存占用、網(wǎng)絡(luò)帶寬、磁盤IO等,影響性能的因素很多,它是一個復(fù)雜的問題。

# 三、基礎(chǔ)知識

能編寫運行正確的程序不一定能做性能優(yōu)化,性能優(yōu)化有更高的要求,這樣講并不是想要嚇阻想做性能優(yōu)化的工程師,而是實事求是講,性能優(yōu)化既需要扎實的系統(tǒng)知識,又需要豐富的實踐經(jīng)驗,只有這樣,你才能具備case by case分析問題解決問題的能力。

所以,相比直接給出結(jié)論,我更愿意多花些篇幅講一些基礎(chǔ)知識,我堅持認(rèn)為底層基礎(chǔ)是理解并掌握性能優(yōu)化技能的前提,值得花費一些時間掌握這些根技術(shù)。

## CPU架構(gòu)

你需要了解CPU架構(gòu),理解運算單元、記憶單元、控制單元是如何既各司其職又相互配合完成工作的。

你需要了解CPU如何讀取數(shù)據(jù),CPU如何執(zhí)行任務(wù)。

你需要了解數(shù)據(jù)總線,地址總線和控制總線的區(qū)別和作用。

你需要了解指令周期:取指、譯指、執(zhí)行、寫回。

你需要了解CPU Pipeline,超標(biāo)量流水線,亂序執(zhí)行。

你需要了解多CPU、多核心、邏輯核、超線程、多線程、協(xié)程這些概念。

## 存儲金字塔

CPU的速度和訪存速度相差200倍,高速緩存跨越這個鴻溝的橋梁,你需要理解存儲金字塔,而這個層次結(jié)構(gòu)思維基于著一個稱為局部性原理(principle of locality),它對軟硬件系統(tǒng)的設(shè)計和性能有著極大的影響。

局部性又分為空間局部性和時間局部性。

### 緩存

現(xiàn)代計算機系統(tǒng)一般有L1-L2-L3三級緩存。

每個CPU核心有獨立的L1、L2高速緩存,所以L1和L2是on-chip緩存;L3是多個CPU核心共享的,它是off-chip緩存。

L1緩存又分為i-cache(指令緩存)和d-cache(數(shù)據(jù)緩存),L1緩存通常只有32K/64KB,速度高達(dá)4 cycles。

L2緩存能到256KB,速度在8 cycles左右。

L3則高達(dá)30MB,速度32 cycles左右。

而內(nèi)存高達(dá)數(shù)G,訪存時延則在200 cycles左右。

所以CPU->寄存器->L1->L2->L3->內(nèi)存->磁盤構(gòu)成存儲層級結(jié)構(gòu),越靠近CPU,存儲容量越小、速度越快、單位成本越高,越遠(yuǎn)離CPU,存儲容量越大、速度越慢、單位成本越低。

### 虛擬存儲器(VM)

進(jìn)程和虛擬地址空間是操作系統(tǒng)的2個核心抽象。

系統(tǒng)中的所有進(jìn)程共享CPU和主存資源,虛擬存儲是對主存的抽象,它為每個進(jìn)程提供一個大的、一致的、私有的地址空間,我們gdb調(diào)試的時候,打印出來的變量地址是虛擬地址。

操作系統(tǒng)+CPU硬件(MMU)緊密合作完成虛擬地址到物理地址的翻譯(映射),這個過程總是沉默的自動的進(jìn)行,不需要應(yīng)用程序員的任何干預(yù)。

每個進(jìn)程有一個單獨的頁表(Page Table),頁表是一個頁表條目(PTE)的數(shù)組,該表的內(nèi)容由操作系統(tǒng)管理,虛擬地址空間中的每個頁(4M或者8M)通過查找頁表找到物理地址,頁表往往是層級式的,多級頁表減少了頁表的存儲需求,命失(Page Fault)將導(dǎo)致頁面調(diào)度(Swapping或者Paging),這個懲罰很重,所以,我們要改善程序的行為,讓它有更好的局部性,如果一段時間內(nèi)訪存的地址過于發(fā)散,將導(dǎo)致顛簸(Thrashing),從而嚴(yán)重影響程序性能。

為了加速地址翻譯,MMU中增加了一個關(guān)于PTE的小的緩存,叫翻譯后備緩沖器(TLB),地址翻譯單元做地址翻譯的時候,會先查詢TLB,只有TLB命失才會查詢高速緩存(L1-2-3)。

## 匯編基礎(chǔ)

了解匯編,了解幾種尋址模式,了解數(shù)據(jù)操作、分支、傳送、控制跳轉(zhuǎn)指令。

理解C語言的if else、while/do while/for、switch case、函數(shù)調(diào)用是怎么翻譯成匯編代碼。

理解ebp+esp寄存器在函數(shù)調(diào)用過程中是如何構(gòu)建和撤銷棧幀的。

理解函數(shù)參數(shù)和返回值是怎么傳遞的。

## 異常和系統(tǒng)調(diào)用

異常會導(dǎo)致控制流突變,異常控制流發(fā)生在計算機系統(tǒng)的各個層次,異??梢苑譃樗念悾?/p>

中斷(interrupt):中斷是異步發(fā)生的,來自處理器外部IO設(shè)備信號,中斷處理程序分上下部。

陷阱(trap):陷阱是有意的異常,是執(zhí)行一條指令的結(jié)果,系統(tǒng)調(diào)用是通過陷阱實現(xiàn)的,陷阱在用戶程序和內(nèi)核之間提供一個像過程調(diào)用一樣的接口“系統(tǒng)調(diào)用”。

故障(fault):故障由錯誤情況引起,它有可能被故障處理程序修復(fù),故障發(fā)生,處理器將控制轉(zhuǎn)移到故障處理程序,缺頁(Page Fault)是經(jīng)典的故障實例

終止(abort):終止是不可恢復(fù)的致命錯誤導(dǎo)致的結(jié)果,通常是硬件錯誤,會終止程序的執(zhí)行。

## 內(nèi)核態(tài)和用戶態(tài)

你需要了解操作系統(tǒng)的一些概念,比如內(nèi)核態(tài)和用戶態(tài),應(yīng)用程序在用戶態(tài)運行我們編寫的邏輯,一旦調(diào)用系統(tǒng)調(diào)用,便會通過一個特定的中斷陷入內(nèi)核態(tài),通過系統(tǒng)調(diào)用號標(biāo)識功能,不同于普通函數(shù)調(diào)用,陷入內(nèi)核態(tài)和從內(nèi)核態(tài)返回需要做上下文切換,需要做環(huán)境變量的保存和恢復(fù)工作,它會帶來額外的消耗,我們編寫的程序應(yīng)避免頻繁做context swap,提升用戶態(tài)的CPU占比是性能優(yōu)化的一個目標(biāo)。

## 進(jìn)程、線程、協(xié)程

在linux內(nèi)核中,進(jìn)程和線程是同樣的系統(tǒng)調(diào)用(clone),進(jìn)程跟線程的區(qū)別:線程是共享存儲空間的,每個執(zhí)行流有一個執(zhí)行控制結(jié)構(gòu)體,這里面會有一個指針,指向地址空間結(jié)構(gòu),一個進(jìn)程內(nèi)的多個線程,通過指向同一地址結(jié)構(gòu)實現(xiàn)共享同一虛擬地址空間。

通過fork創(chuàng)建子進(jìn)程的時候,不會馬上copy數(shù)據(jù),而是推遲到子進(jìn)程對地址空間進(jìn)行改寫,這樣做是合理的,此即為COW(Copy On Write),在應(yīng)用程序開發(fā)中,也有大量的類似借鑒。

協(xié)程是用戶態(tài)的多執(zhí)行流,C語言提供makecontext/getcontext/swapcontext系列接口,很多協(xié)程庫也是基于這些接口實現(xiàn)的,微信的libco通過hook慢速系統(tǒng)調(diào)用(比如write,read)做到靜默替換,非常巧妙。

## 鏈接

C/C++源代碼經(jīng)編譯鏈接后產(chǎn)生可執(zhí)行程序,其中數(shù)據(jù)和代碼分段存儲,我們寫的函數(shù)將進(jìn)入text節(jié),全局?jǐn)?shù)據(jù)將進(jìn)入數(shù)據(jù)段,未初始化的全局變量進(jìn)入bss,堆和棧向著相反的方向生長,局部變量在棧里,參數(shù)和返回值也會通過棧傳遞。

想要程序運行的更快,最好把相互調(diào)用,關(guān)系緊密的函數(shù)放到代碼段相近的地方,這樣能提高icache命中性。減少代碼量、減少函數(shù)調(diào)用、減少函數(shù)指針同樣能提高i-cache命中性。

內(nèi)聯(lián)既避免了棧幀建立撤銷的開銷,又避免了控制跳轉(zhuǎn)對i-cache的沖刷,所以有利于性能。同樣,關(guān)鍵路徑的性能敏感函數(shù)也應(yīng)該避免遞歸函數(shù)。

減少函數(shù)調(diào)用(就地展開)跟封裝是相違背的,有時候,為了性能,我們不得不破壞封裝和損傷可讀性的代碼,這是一個權(quán)衡利弊的問題。

## 常識和數(shù)據(jù)

CPU拷貝數(shù)據(jù)一般一秒鐘能做到幾百兆,當(dāng)然每次拷貝的數(shù)據(jù)長度不同,吞吐不同。

一次函數(shù)執(zhí)行如果耗費超過1000 cycles就比較大了(刨除調(diào)用子函數(shù)的開銷)。

pthread_mutex_t首次加解鎖大概耗時4000-5000 cycles左右,之后,每次加解鎖大概120 cycles,O2優(yōu)化的時候100 cycles,spinlock耗時略少。

lock內(nèi)存總線+xchg需要50 cycles,一次內(nèi)存屏障要50 cycles。

有一些無鎖的技術(shù),比如linux kernel里的kfifo,主要使用了整型回繞+內(nèi)存屏障。

# 四、怎么做性能優(yōu)化(TODO)

兩個?向:提?運?速度 + 減少計算量。

性能優(yōu)化監(jiān)控先?,要基于數(shù)據(jù)??基于猜測,要搭建能盡量模擬真實運?狀態(tài)的壓?測試環(huán)境,在此基于上獲取的profiling數(shù)據(jù)才是有?的。

方法論:監(jiān)控 -> 分析 -> 優(yōu)化 三部曲

# 五、幾個具體問題(TODO)

1. 如何定位CPU瓶頸?

2. 如何定位IO瓶頸?

3. 如何定位?絡(luò)瓶頸?

4.如何定位鎖的問題?

大家都知道鎖會引入額外開銷,但鎖的開銷到底有多大,估計很多人沒有實測過,我可以給一個數(shù)據(jù),一般單次加解鎖100 cycles,spinlock或者cas更快一點。

使用鎖的時候,要注意鎖的粒度,但鎖的粒度也不是越小越好,太大會增加撞鎖的概率,太小會導(dǎo)致代碼更難寫。

多線程場景下,如果cpu利用率上不去,而系統(tǒng)吞吐也上不去,那就有可能是鎖導(dǎo)致的性能下降,這個時候,可以觀察程序的sys cpu和usr cpu,這個時候通過perf如果發(fā)現(xiàn)lock的開銷大,那就沒錯了。

5. 如何提?并發(fā)能??

# 六、實踐經(jīng)驗和案例分析(TODO)

這塊內(nèi)容非常多,需要好好說,在此先列一個提綱

TODO

# 七、性能優(yōu)化黑科技

# 八、小結(jié)

 

還沒想好,TODO

 

責(zé)任編輯:武曉燕 來源: 碼磚雜役
相關(guān)推薦

2020-08-11 10:58:32

戴爾

2019-03-04 16:09:22

iQOO

2023-04-03 14:25:08

大數(shù)據(jù)機器學(xué)習(xí)

2017-12-12 14:26:16

數(shù)據(jù)庫PostgreSQL邏輯優(yōu)化

2021-01-13 10:05:31

數(shù)字化轉(zhuǎn)型數(shù)字化CIO

2015-08-18 15:37:31

數(shù)據(jù)中心災(zāi)備

2017-11-01 21:33:40

python

2015-12-29 10:24:19

管理工具集群管理

2020-05-13 14:15:25

if-else代碼前端

2018-05-20 11:25:45

520程序員表白

2022-07-26 09:48:55

微服務(wù)服務(wù)AKF

2020-11-10 07:08:08

API程序外接口

2018-06-25 13:37:13

2009-02-24 13:38:38

2019-01-22 11:22:47

云計算CIO云品牌

2019-03-08 10:08:41

網(wǎng)絡(luò)程序猿代碼

2025-02-27 10:30:00

JavaScript數(shù)組代碼

2020-02-25 22:41:41

程序員技能開發(fā)者

2010-11-15 16:20:33

Oracle系統(tǒng)優(yōu)化

2023-11-13 08:34:01

Java編程習(xí)慣
點贊
收藏

51CTO技術(shù)棧公眾號