前言
最近閱讀了計(jì)算機(jī)相關(guān)基礎(chǔ)課程泡挺,對(duì)代碼優(yōu)化有一些見(jiàn)解媳溺。
代碼優(yōu)化三大方向
- 運(yùn)行時(shí)占用更少的存儲(chǔ)空間
- 程序執(zhí)行時(shí)消耗更少的指令數(shù)
- 盡可能的降低線(xiàn)程切換
接下來(lái)我對(duì)這三點(diǎn)加以解釋
運(yùn)行時(shí)占用更少的存儲(chǔ)空間
這里所說(shuō)的存儲(chǔ)空間是:程序運(yùn)行時(shí),需要操作的數(shù)據(jù)占用的空間大小。
為了解釋這個(gè)問(wèn)題,我舉個(gè)栗子
理發(fā)師的挎包
我去理發(fā)時(shí)江耀,發(fā)現(xiàn)大多數(shù)的理發(fā)師在腰間夸一個(gè)包系宫,放一些常用的理發(fā)工具缤至,這樣他在理發(fā)時(shí)何恶,需要什么就先從挎包里看一下唬涧,如果有狮荔,那就直接拿出來(lái)用受葛,如果沒(méi)有纲堵,他就到柜臺(tái)上面找一下。
計(jì)算機(jī)和理發(fā)師挺像的愚隧,相似點(diǎn)如下
- 理發(fā)師 就是 CPU
- 挎包 就是 緩存
- 柜臺(tái) 就是 內(nèi)存
- 顧客 就是 程序
如果我去理發(fā),我的發(fā)型很簡(jiǎn)單荞胡,卡尺就行窖梁,理發(fā)師挎包里放一個(gè)電動(dòng)理發(fā)器和剪刀就行纵刘。
如果陳妍希去理發(fā)舵抹,人家對(duì)自己的發(fā)型要求很高,理發(fā)師給陳妍希理發(fā)會(huì)使用很多工具沧烈。如果他的挎包很小柬泽,裝不了很多工具,那么理發(fā)師在理發(fā)的時(shí)候第煮,當(dāng)需要的工具不在挎包里時(shí)解幼,他就要跑去到柜臺(tái)那。
假如你的經(jīng)濟(jì)條件有限包警,你只能去便宜的理發(fā)店撵摆,理發(fā)師的挎包不是很大,但是你想快點(diǎn)理完頭發(fā)害晦,那你會(huì)選擇什么樣的發(fā)型特铝?
- 復(fù)雜的發(fā)型,理發(fā)師會(huì)手忙腳亂壹瘟,耽誤時(shí)間鲫剿。
- 簡(jiǎn)單的發(fā)型,理發(fā)師游刃有余稻轨,很輕松的就能理完頭發(fā)灵莲。
計(jì)算機(jī)中的解釋
計(jì)算機(jī)執(zhí)行程序時(shí),為了提高執(zhí)行速度殴俱,在cpu和內(nèi)存之間設(shè)置了一個(gè)高速緩存政冻,cpu和高速緩存之間的交互非趁兜郑快。當(dāng)程序運(yùn)行時(shí)赠幕,會(huì)優(yōu)先從緩存中獲取數(shù)據(jù)俄精,如果獲取成功,他不會(huì)跑到內(nèi)存里找榕堰。如果在緩存中獲取失敗,他就要到內(nèi)存里找數(shù)據(jù)嫌套。
在這一點(diǎn)上逆屡,我們能做的就是在存儲(chǔ)數(shù)據(jù)時(shí),優(yōu)先使用線(xiàn)性存儲(chǔ)結(jié)構(gòu)踱讨,因?yàn)檫@樣的數(shù)據(jù)是一個(gè)挨著一個(gè)魏蔗,如果將人來(lái)代替這些數(shù)據(jù)的的話(huà),線(xiàn)性存儲(chǔ)就是讓些人站成一個(gè)隊(duì)列痹筛,一個(gè)方陣莺治,節(jié)約占地資源。
消耗更少的指令數(shù)
上學(xué)遲到
小強(qiáng)和小紅都是在一個(gè)院子長(zhǎng)大的帚稠,但是他們兩個(gè)都不認(rèn)識(shí)彼此谣旁,直到上了小學(xué)。小學(xué)和他們的家隔了一個(gè)小樹(shù)林滋早,小強(qiáng)比較懶榄审,上學(xué)經(jīng)常遲到,被老師罰站杆麸。
小紅總是看到小強(qiáng)罰站搁进,就課下問(wèn)他:你家是不是在山溝里啊,天天上學(xué)都遲到昔头。
小強(qiáng)說(shuō)我家在某某院
小紅:咦饼问,咱們住一個(gè)院啊 ,你難道是爬過(guò)來(lái)了嗎
小強(qiáng):我每天需要繞個(gè)小樹(shù)林揭斧,再說(shuō)我也懶...
小紅:明天我領(lǐng)你鉆小樹(shù)林去...
小紅每天是穿過(guò)小樹(shù)林上學(xué)的莱革,自從小強(qiáng)知道了怎么穿小樹(shù)林,他上學(xué)就不會(huì)繞個(gè)遠(yuǎn)道了未蝌,節(jié)省了時(shí)間驮吱,不再遲到。
類(lèi)比計(jì)算機(jī)
- 小強(qiáng):cpu
- 程序:上學(xué)的路程
要做到這一點(diǎn)萧吠,對(duì)大家要求比較高左冬,我舉幾個(gè)簡(jiǎn)單的方法
- 在使用高級(jí)集合框架時(shí),如果這些集合框架的存儲(chǔ)結(jié)構(gòu)是線(xiàn)性結(jié)構(gòu)纸型,這些集合框架會(huì)隨著數(shù)據(jù)量的增加拇砰,而調(diào)整大小梅忌。這個(gè)調(diào)整大小的過(guò)程比較消耗資源:先找到一個(gè)更大的內(nèi)存空間,把老的數(shù)據(jù)移動(dòng)到新的內(nèi)存空間除破。這就需要我們?cè)谑褂们邦A(yù)估需要存儲(chǔ)的數(shù)據(jù)的數(shù)量牧氮,在使用這些集合框架時(shí),明確的給它一個(gè)初始大小瑰枫,這樣可以盡可能的減少調(diào)整大小的次數(shù)踱葛,減少指令數(shù)。
- 優(yōu)先使用線(xiàn)性的數(shù)據(jù)結(jié)構(gòu)光坝。減少使用基于哈希的數(shù)據(jù)結(jié)構(gòu)尸诽,比如hashMap,hashset盯另,這些高級(jí)結(jié)構(gòu)不僅占用空間性含,而且會(huì)增加指令數(shù)。比如hashmap鸳惯,它提供的功能是根據(jù)一個(gè)key商蕴,將其對(duì)應(yīng)的數(shù)據(jù)找到。支撐這樣功能的實(shí)現(xiàn)避免不了使用更多的指令芝发。
盡可能的降低線(xiàn)程切換
黃燜雞米飯
有天小紅和小蘭一起去吃飯绪商,到了山西刀削面,他們都點(diǎn)了黃燜雞米飯后德,過(guò)了一會(huì)部宿,小紅的先上了,小蘭就繼續(xù)等瓢湃,等小紅快吃完了理张,小蘭的才做好。小蘭就很納悶了绵患,問(wèn)老板原因雾叭,老板說(shuō),雞塊不夠了落蝙,我們又進(jìn)了雞塊织狐,花了一點(diǎn)時(shí)間。
我們想象一下后廚里的情況筏勒。廚房里有一個(gè)廚師移迫,他負(fù)責(zé)做黃燜雞米飯,當(dāng)他發(fā)現(xiàn)雞塊只剩一份的量時(shí)管行,就給老板說(shuō)厨埋,讓他再進(jìn)點(diǎn)雞塊。廚師做完黃燜雞米飯捐顷,又去做油潑面荡陷,他正在做油潑面的時(shí)候雨效,老板把雞塊買(mǎi)回來(lái)了。等到他做完油潑面后废赞,他才開(kāi)始做黃燜雞米飯徽龟。
線(xiàn)程切換就是廚師從做一個(gè)菜轉(zhuǎn)換到做另外一個(gè)菜的行為。 廚師做完黃燜雞唉地,然后做油潑面据悔,最后再做黃燜雞。
本來(lái)廚師可以一次做兩份黃燜雞米飯渣蜗,卻因?yàn)殡u塊不夠屠尊,他只能先做一份,期間又要做一個(gè)油潑面耕拷。他好累啊。
那為了讓廚師和顧客都滿(mǎn)意托享,老板就要多備一點(diǎn)雞塊骚烧,爭(zhēng)取不讓廚師做同一種飯兩次。 這就是降低線(xiàn)程切換
計(jì)算機(jī)中的線(xiàn)程切換
我們?cè)谑褂糜?jì)算機(jī)時(shí)闰围,感覺(jué)計(jì)算機(jī)很聰明赃绊,它能同時(shí)運(yùn)行很多程序,其實(shí)是計(jì)算機(jī)給你的一個(gè)錯(cuò)覺(jué):計(jì)算機(jī)是定義了一個(gè)時(shí)間段羡榴,規(guī)定每個(gè)程序只能運(yùn)行這么長(zhǎng)時(shí)間碧查,時(shí)間到了,就給下個(gè)程序運(yùn)行校仑。只是因?yàn)閏pu現(xiàn)在的性能很高忠售,做這些事情很快,我們就無(wú)感知了迄沫。
大部分的程序其實(shí)都能在這個(gè)時(shí)間段內(nèi)完成稻扬。但是也有一些其他情況導(dǎo)致cpu放棄執(zhí)行當(dāng)前程序:需要的數(shù)據(jù)不可用。
出現(xiàn)數(shù)據(jù)不可用的情況
- 這個(gè)數(shù)據(jù)正在被別人使用
- 這個(gè)數(shù)據(jù)不能夠被使用羊瘩,已經(jīng)過(guò)期或者失效
- 這個(gè)數(shù)據(jù)已經(jīng)沒(méi)有了
- 這個(gè)數(shù)據(jù)正在生產(chǎn)
為了降低線(xiàn)程切換泰佳,我們可以這樣做
- 盡可能使用自己私有的數(shù)據(jù),不和其他人共享尘吗。
- 如果必須使用共享數(shù)據(jù)逝她,那么在寫(xiě)程序時(shí),盡可能將所有需要的資源全部拿到手睬捶。
- 如果你的程序特點(diǎn)是計(jì)算量比較大黔宛,那就避免使用多線(xiàn)程。盡管你認(rèn)為你的程序很復(fù)雜侧戴,但是cpu根本不關(guān)心宁昭,它會(huì)把你程序當(dāng)成屁給放了跌宛。因?yàn)閏pu的計(jì)算速度已經(jīng)非常快了积仗,執(zhí)行的你的程序就是瞬間疆拘。但如果你在程序里用到了多線(xiàn)程,那么cpu就不得不進(jìn)行線(xiàn)程切換寂曹。線(xiàn)程切換消耗的cpu資源遠(yuǎn)遠(yuǎn)大于cpu執(zhí)行你程序消耗的資源哎迄。
后記
基礎(chǔ)很重要。
我記得一個(gè)四十多歲當(dāng)上院士的數(shù)學(xué)家說(shuō)隆圆,他小時(shí)候?qū)W數(shù)學(xué)漱挚,每個(gè)定理都要自己證明,并且他不怎么做題目渺氧。當(dāng)你足夠的了解基礎(chǔ)知識(shí)旨涝,你就不會(huì)被誤導(dǎo),也有更多的時(shí)間往深處學(xué)習(xí)侣背。