6.12 通過內存緩存來提升性能
當在進行大量的計算時,提升性能最直接有效的一種方式就是避免重複計算。通過在內存中緩存和重複利用相同計算的結果,稱之爲內存緩存。最明顯的例子就是生成斐波那契數列的程序(詳見第 6.6 和 6.11 節):
要計算數列中第 n 個數字,需要先得到之前兩個數的值,但很明顯絕大多數情況下前兩個數的值都是已經計算過的。即每個更後面的數都是基於之前計算結果的重複計算,正如示例 6.11 fibonnaci.go 所展示的那樣。
而我們要做就是將第 n 個數的值存在數組中索引爲 n 的位置(詳見第 7 章),然後在數組中查找是否已經計算過,如果沒有找到,則再進行計算。
程序 Listing 6.17 - fibonacci_memoization.go 就是依照這個原則實現的,下面是計算到第 40 位數字的性能對比:
- 普通寫法:4.730270 秒
- 內存緩存:0.001000 秒
內存緩存的優勢顯而易見,而且您還可以將它應用到其它類型的計算中,例如使用 map(詳見第 7 章)而不是數組或切片(Listing 6.21 - fibonacci_memoization.go):
package main
import (
"fmt"
"time"
)
const LIM = 41
var fibs [LIM]uint64
func main() {
var result uint64 = 0
start := time.Now()
for i := 0; i < LIM; i++ {
result = fibonacci(i)
fmt.Printf("fibonacci(%d) is: %d\n", i, result)
}
end := time.Now()
delta := end.Sub(start)
fmt.Printf("longCalculation took this amount of time: %s\n", delta)
}
func fibonacci(n int) (res uint64) {
// memoization: check if fibonacci(n) is already known in array:
if fibs[n] != 0 {
res = fibs[n]
return
}
if n <= 1 {
res = 1
} else {
res = fibonacci(n-1) + fibonacci(n-2)
}
fibs[n] = res
return
}
內存緩存的技術在使用計算成本相對昂貴的函數時非常有用(不僅限於例子中的遞歸),譬如大量進行相同參數的運算。這種技術還可以應用於純函數中,即相同輸入必定獲得相同輸出的函數。