Go語言字串高效拼接(三)

2021-09-11 12:27:44 字數 2154 閱讀 8968

既然要優化builder拼接,那麼我們起碼知道他慢在哪,我們繼續使用我們上篇文章的測試用例,執行看下效能。

builder10-8     5000000     258 ns/op       480 b/op        4 allocs/op

builder100-8 1000000 2012 ns/op 6752 b/op 8 allocs/op

builder1000-8 100000 21016 ns/op 96224 b/op 16 allocs/op

builder10000-8 10000 195098 ns/op 1120226 b/op 25 allocs/op

複製**

針對既然要優化builder拼接,採取了10、100、1000、10000四種不同數量的字串進行拼接測試。我們發現每次操作都有不同次數的記憶體分配,記憶體分配越多,越慢,如果引起gc,就更慢了,首先我們先優化這個,減少記憶體分配的次數。

通過cpuprofile,檢視生成的火焰圖可以得知,runtime.growslice函式會被頻繁的呼叫,並且時間佔比也比較長。我們檢視builder.writestring的源**:

func

(b *builder)

writestring

(s string)

(int, error)

複製**

既然問題的原因找到了,那麼我們就可以優化了,核心手段就是減少runtime.growslice呼叫,甚至不呼叫。照著這個思路的話,我們就要提前為b.buf分配好容量cap。幸好builder為我們提供了擴充容量的方法grow,我們在進行writestring之前,先通過grow方法,擴充好容量即可。

現在開始改造我們的stringbuilder函式。

func

stringbuilder

(p string,cap

int)

string

複製**

增加乙個引數cap,讓使用者告訴我們需要的容量大小。grow方法的實現非常簡單,就是乙個通過make函式,擴充b.buf大小,然後再拷貝b.buf的過程。

func

(b *builder)

grow

(n int)

複製**

那麼現在我們的效能測試用例變成如下:

func

benchmarkstringbuilder10

(b *testing.b) }

func

benchmarkstringbuilder1000

(b *testing.b) }

複製**

為了說明情況和簡短**,這裡只有10和1000個元素的用例,其他類似。為了把效能優化到極致,我一次性把需要的容量分配足夠。現在我們再執行效能(benchmark)測試**。

builder10-8     10000000    123 ns/op       352 b/op    1 allocs/op

builder100-8 2000000 898 ns/op 2688 b/op 1 allocs/op

builder1000-8 200000 7729 ns/op 24576 b/op 1 allocs/op

builder10000-8 20000 78678 ns/op 237568 b/op 1 allocs/op

複製**

效能足足翻了1倍多,只有1次記憶體分配,每次操作占用的記憶體也減少了一半多,降低了gc。

字串拼接的系列,到這裡結束了,一共三個系列,希望對大家所有幫助。

go字串拼接方法

go 語言中的字串是唯讀的 拼接方式 這種方式是我在寫golang經常用的方式,go語言用 拼接,php使用.拼接,不過由於golang中的字串是不可變的型別,因此用 連線會產生乙個新的字串對效率有影響。go語言中文文件 www.topgoer.com func main sprintf函式 s1 ...

Go語言字串拼接的三種方式

通過建立乙個緩衝byte型別的緩衝器str1,然後通過writestring方法將傳入的字串放入緩衝器的尾部,已達到拼接的作用,然後呼叫緩衝器str1的string 方法,可以返回放入緩衝器中的內容 實際返回的是緩衝器中未讀的部分 返回型別為string。var str1 bytes.buffer ...

拼接字串

border 1 class box 標籤名稱th 是否顯示th 標籤順序th tr thead 首頁td class check 是option 否option select td class number 1option 2option 3option 4option 5option 6opti...