如何進行邏輯優化代碼?
本文邀請jinbiao來回答,與你分享邏輯代碼優化的方法~
邏輯代碼計算優化在不考慮面向對象的情況下,先讓我們先回憶下c語言中的3大結構。
1、順序結構
2、分支(條件)結構
3、循環結構
這三個結構任意組合構成了我們書寫的邏輯代碼(算法)。下面我們就根據這常用的三種結構進行調優。注意,下文中的使用的語言為JavaScript,但考慮大的是大部分語言的情況。
代碼在計算機中實際都是一條條語句執行的,分支和循環結構在使用了jump語句實現了語句跳轉之后,實際上也變成了一個順序結構。如果代碼以順序結構執行,則可以通過程序計數器自增讓代碼順序執行。如果是jump跳轉語句則會發生尋址,計算等額外步驟。
[ 匯編 ]
這里c語言代碼中寫了一個普通的循環。但是在計算機中實際執行時類似右邊goto版本的。每一個goto會加重計算機的計算,所以在考慮性能的情況下盡量使用順序結構。
優化循環常見的循環有
1、while
2、for
3、do…while
注意的是循環中while與for是先判斷在開始循環,do…while是先運行一次后判斷在開始循環
循環中兩種方案調優
1、減少每次循環處理的事務
2、減少循環的次數
在循環判斷條件中,通常我們將某個對象的屬性進行判斷比如
實際上在計算機的語句為
初始化(一次)
一次i初始化(var i)
一次i賦值(i = 0)
判斷(n次)
i值查找(i)
array值查找(array)
通過array找到length(array.length)
i 與 length 比較(i < array.length)
后處理,自增(n - 1次)
i取值(i)
計算i + 1(i + 1)
將結果賦值給(i = i + 1)
這次判斷實際上有四個語句組成,在看看下面的代碼
在這個判斷中實際上在計算機的語句為:
一次i值查找。
一次len值查找
通過array找到length
i 與 length 比較
這里在單次循環中語句減少了一條。在多次循環下,將減少了n條計算機語句。
如果是簡單的數值比較我們還可以使用倒序循環方式
這次實際上在計算機的語句為
初始化(一次)
i初始化(var i)
array值查找(array)
通過array找到length(array.length)
i賦值(i = array.length)
判斷(n次)
i取值(i)
計算i - 1(i - 1)
將結果賦值給(i = i - 1)
后處理,自增(n-1次)
實際上這樣的語句確實少了挺多,但是必須是在順序無關和數值比較的前提下。因為部分語言會提供數值與布爾值的自動轉換(像java這么寫就會報錯)
減少使用遞歸
談到循環,自然也會談到遞歸。遞歸最簡單說就是某個函數繼續調用某個函數,一般是自己調用自己。
一個進程。有數據區,堆棧,PCB等內容。堆棧的大小在進程開啟的時候基本確定,棧能存儲運行時的局部變量,和函數調用信息。如果發生遞歸,則會在棧中持續添加內容。若執行函數需要用到局部變量,或者調用函數不是最后一句時。將會發生中斷。中斷后,本次運行的上下文環境也會被保存進棧內,形成一個調用棧。
[ 遞歸 ]
發生一次中斷,會觸發CPU的中斷處理,保存中斷信息現場,指令跳轉。恢復時又會跳轉指令,恢復中斷現場信息。如果非必要,請不要使用遞歸。
棧的大小是固定的,如果超過棧的大小,就會有爆棧的可能(著名的stack overflow)。部分語言有尾調用優化,可以讓遞歸不保存中斷信息。
優化選擇
常見的選擇有:
if…else 更適合范圍匹配
switch…case 更適合單值匹配
不管使用的是if…else還是switch…case,判斷都是按書寫的順序開始執行的。所以我們應該把最可能出現的情況放在第一位。
由于選擇結構也會觸發指令跳轉,我們應該使用嵌套的if…else,使用樹的形式,讓到達每一個結果的情況盡可能的少。