最近一個客戶提問說,我的系統(tǒng)順序執(zhí)行不是也很快嘛,為什么要并發(fā)來執(zhí)行呢?
這個問題初看很簡單,我仔細想了一下,其實不太容易回答,尤其是現(xiàn)在高級語言越來越多,導致開發(fā)人員對系統(tǒng)的理解比較困難。其實就是對系統(tǒng)的性能理解存在很多偏差。
第一個問題,程序執(zhí)行時間,是如何來計算的?我們知道,當前的系統(tǒng)幾乎都是馮諾依曼架構(gòu)的,它順序的執(zhí)行指令(也就是程序編譯完成的結(jié)果),來完成一個一個的功能。每一條指令,執(zhí)行的時候,都包含了幾個時鐘周期。比如,一個指令可能包含1個時鐘周期,也可能包含多個。所謂時鐘,就是我們經(jīng)??吹降?,你的電腦的主頻,其實是cpu主頻,是多少G的,就是一秒鐘有多少個時鐘周期。假設你的代碼要執(zhí)行5萬條指令,平均每條指令有2個時鐘周期,那么執(zhí)行完成這一段代碼,就需要10萬個時鐘周期,再根據(jù)主頻,我們就能夠知道,需要多少時間了。
第二個問題,為什么并發(fā)執(zhí)行速度更快?其實有幾個原因:1)我們的cpu是多內(nèi)核多線程的。每個線程可以獨立執(zhí)行一個指令序列。比如16線程的cpu,可以同時執(zhí)行16段代碼,如果你的代碼只允許單個執(zhí)行,那么只使用了1個線程,其他的15個在“休息”,當然不夠快。如果你讓它同時跑16并發(fā),肯定能夠得到更快的執(zhí)行速度。2)操作系統(tǒng)調(diào)度。我們知道,當執(zhí)行代碼的時候,比如你遇到一個通訊代碼,要從一個“句柄”中讀取信息,那么這個程序就會陷入等待狀態(tài),操作系統(tǒng)就會“掛起”它,直到這個信息發(fā)過來,觸發(fā)了一個“中斷”,來喚醒了這個代碼,讓它繼續(xù)執(zhí)行。當代碼被掛起,其實操作系統(tǒng)就可以安排其他的程序進來執(zhí)行。所以,雖然你的cpu有16線程,但是它可以執(zhí)行更多的并發(fā)。
第三個問題,為什么有的代碼,看起來長度差不多,但是卻很慢?我們知道,程序代碼如果使用了“系統(tǒng)調(diào)用”,那么其實這個功能是操作系統(tǒng)提供的,會進入操作系統(tǒng)的另外一個狀態(tài),導致執(zhí)行了一大堆你看不到的代碼。如果你的代碼沒有系統(tǒng)調(diào)用,原則上可以比使用系統(tǒng)調(diào)用的代碼跑的更快。舉個例子,比如你的代碼用到了動態(tài)內(nèi)存,這個內(nèi)存從哪里來呢?從操作系統(tǒng)的“堆”來,那么就要去操作系統(tǒng)的“堆”申請一片內(nèi)存。如果你想讓它很快,那么你可以開一片大的內(nèi)存在本程序內(nèi),一般使用局部變量。局部變量開在哪里?一般在“棧”里面。你會發(fā)現(xiàn),性能提升了非常多。
以上,我們解釋了,程序執(zhí)行占用cpu和時間的問題,以及為什么并發(fā)執(zhí)行的代碼往往會效率更高。當然,如果你的并發(fā)設置的過高,也會起反作用:由于cpu線程的頻繁調(diào)度導致性能下降。
下面我們說一下,如何優(yōu)化代碼。首先,要優(yōu)化單個代碼的執(zhí)行速度,就是縮短執(zhí)行時間。比如,一段代碼原來執(zhí)行一次,需要2秒。如果你優(yōu)化到0.2秒(就是200毫秒),那么速度就提升了10倍。代碼優(yōu)化,主要的就是算法,減少指令執(zhí)行條數(shù),避免循環(huán)嵌套、甚至循環(huán)展開。技術(shù)手段很多,有興趣可以自己搜索研究。
當單個的代碼執(zhí)行速度提升,我們就可以通過性能測試工具(比如澤眾performanceRunner性能測試工具)來并發(fā)執(zhí)行,看看在大并發(fā)之下,會不會由于資源沖突或者競爭導致的性能急速下降。單獨執(zhí)行速度快的代碼,也可能在一定并發(fā)到達之后,忽然慢下來的。比如,你的數(shù)據(jù)庫沒有索引。
這篇文章的目的是幫助我們理解,什么是性能,從cpu和指令的角度看,如何看待執(zhí)行速度。
推薦閱讀:
本文內(nèi)容不用于商業(yè)目的,如涉及知識產(chǎn)權(quán)問題,請權(quán)利人聯(lián)系SPASVO小編(021-60725088-8054),我們將立即處理,馬上刪除。