Go語言效能優化 For Range 效能研究

2021-09-13 04:08:42 字數 4320 閱讀 8215

如果我們要遍歷某個陣列,map集合,slice切片等,go語言(golang)為我們提供了比較好用的for range方式。range是乙個關鍵字,表示範圍,和for配合使用可以迭代陣列,map等集合。它的用法簡潔,而且map、channel等也都是用for range的方式,所以在編碼中我們使用for range進行迴圈迭代是最多的。對於這種最常使用的迭代,尤其是和for i=0;ifor range的使用非常簡單,這裡演示下兩種集合型別的使用。

package main

import "fmt"

func main()

for i,age:=range ages

}

這是針對 slice 切片的迭代使用,使用range關鍵字返回兩個變數i,age,第乙個是 slice 切片的索引,第二個是 slice 切片中的內容,所以我們列印出來:

0 10

1 20

2 30

關於go語言 slice 切片的,可以參考我以前寫的這篇 go語言實戰筆記(五)| go 切片

下面再看看map(字典)的for range使用示例。

package main

import "fmt"

func main()

for name,age:=range ages

}

在使用for range迭代map的時候,返回的第乙個變數是key,第二個變數是value,也就是我們例子中對應的nameages。我們執行程式看看輸出結果。

張三 15

李四 20

王武 36

這裡需要注意的是,for range map返回的k-v鍵值對順序是不固定的,是隨機的,這次可能是張三-15第乙個出現,下一次執行可能是王武-36第乙個被列印了。

關於map更詳細的可以參考我以前的一篇文章 go語言實戰筆記(六)| go map。

比如對於 slice 切片,我們有兩種迭代方式:一種是常規的for i:=0;i為了測試,寫了這兩種迴圈迭代 slice 切片的函式,從實現上看,他們的邏輯是一樣的,保證我們可以在同樣的情況下測試。

import "testing"

const n = 1000

func initslice() string

}

現在,我們再次進行 benchmark 效能測試,看看效果。

benchmarkforslice-4              5000000    280 ns/op

benchmarkrangeforslice-4 5000000 277 ns/op

恩,和我們想的一樣,效能上來了,和常規的for迴圈持平了。原因就是我們通過_捨棄了元素的複製,然後通過s[i]獲取迭代的元素,既提高了效能,又達到了目的。

func rangeformap1(m map[int]string) 

}const n = 1000

func initmap() map[int]string

return m

}func benchmarkrangeformap1(b *testing.b)

}

飛雪無情的部落格

以上示例是map遍歷的函式以及benchmark測試,我都寫在一起了,執行測試看一下效果。

benchmarkforslice-8              5000000    298 ns/op

benchmarkrangeforslice-8 3000000 475 ns/op

benchmarkrangeformap1-8 100000 14531 ns/op

相比 slice 來說,map的遍歷的效能更差,可以說是慘不忍睹。好,我們開始下優化,思路也是減少值得拷貝。測試中的rangeforslice也慢的原因是我把rangeforslice還原成了值得拷貝,以便於對比效能。

func rangeformap2(m map[int]string) 

}func benchmarkrangeformap2(b *testing.b)

}

再次執行下效能測試看下效果。

benchmarkforslice-8              5000000               298 ns/op

benchmarkrangeforslice-8 3000000 475 ns/op

benchmarkrangeformap1-8 100000 14531 ns/op

benchmarkrangeformap2-8 100000 23199 ns/op

額,是不是發現點不對,方法benchmarkrangeformap2的效能明顯下降了,這個可以從每次操作的耗時看出來(雖然效能測試秒執行的次數還是一樣)。和我們上面測試的slice不一樣,這次不止沒有提公升,反而下降了。

繼續修改map2函式的實現為:

func rangeformap2(m map[int]person) 

}

什麼都不做,只迭代,再次執行效能測試。

benchmarkforslice-8              5000000               301 ns/op

benchmarkrangeforslice-8 3000000 478 ns/op

benchmarkrangeformap1-8 100000 14822 ns/op

benchmarkrangeformap2-8 100000 14215 ns/op

*我們驚奇的發現,什麼都不做,和獲取k-v值的操作效能是一樣的,和slice完全不一樣,不是說for range值拷貝損耗效能呢?都哪去了?大家猜一猜,可以結合下一節的原理實現通過檢視源**,我們可以發現for range的實現是:

// for init ; cond ; post

並且對於slice,map等各有具體不同的編譯實現,我們先看看for range slice的具體實現

// the loop we generate:

// for_temp := range

// len_temp := len(for_temp)

// for index_temp = 0; index_temp < len_temp; index_temp++

先是對要遍歷的 slice 做乙個拷貝,獲取長度大小,然後使用常規for迴圈進行遍歷,並且返回值的拷貝。

再看看for range map的具體實現:

// the loop we generate:

// var hiter map_iteration_struct

// for mapiterinit(type, range, &hiter); hiter.key != nil; mapiternext(&hiter)

也是先對map進行了初始化,因為map*hashmap,所以這裡其實是乙個*hashmap指標的拷貝。

flysnow_org或者**

C語言效能優化

1 資料型別 1 如果確定整數非負,應直接使用unsigned int,處理器處理無符號unsigned 整形數的效率遠遠高於有符號signed整形數 2 float可以用int替代,如果需要結果精確到小數點後n位,可以將其乘以n 10,結果盡可能晚的把它轉換為浮點型數字 3 區域性變數盡可能的不使...

從Baa開發中總結Go語言效能漸進優化

在go生態已經有很多web框架,但感覺沒有乙個符合我們的想法,我們想要乙個簡潔高效的核心框架,提供路由,context,中介軟體和依賴注入,而且拒絕使用正則和反射,於是我們開始構建baa框架。一開始使用最簡單的通俗寫法實現了第一版的功能,基本可用,但是效能爛到爆,優化之路漫漫開啟。最好的文章應該是每...

C語言效能優化 使用位運算

使用位操作可以減少除法和取模的運算。在電腦程式中資料的位是可以操作的最小資料單位,理論上可以用 位運算 來完成所有的運算和操作。一般的位操作是用來控制硬體的,或者進行資料變換,但是,靈活的位操作可以有效地提高程式執行的效率。例如 方法g int i,j i 257 8 j 456 32 方法h in...