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