Go 庫(kù)bytes.Buffer和strings.Builder使用及性能對(duì)比
前言
字符串拼接是老生常談了。在 Go 語(yǔ)言中,常見(jiàn)的拼接字符串的方法有:用+號(hào),或者使用fmt包的Sprintf。
str1 := "a" + "b" // str1: "ab"
str2 := fmt.Sprintf("%s%s", "a", "b") // str2: "ab"
字符串低層是不可修改的,所以每次拼接字符串,都需要重新分配內(nèi)存。如果需要頻繁拼接字符串,上面兩種方法可能性能低下。我們寫下壓測(cè)代碼
// 使用 + 拼接字符串
func BenchmarkConcatStrWithPlus(b *testing.B) {
str := ""
for i := 0; i < b.N; i++ {
str += "test"
}
}
// 使用 Sprintf 拼接字符串
func BenchmarkConcatStrWithSprintf(b *testing.B) {
str := ""
for i := 0; i < b.N; i++ {
str = fmt.Sprintf("%s%s", str, "test")
}
}
執(zhí)行: go test -bench . -benchmem ,得到以下結(jié)果。這個(gè)壓測(cè)結(jié)果,留著跟下文的優(yōu)化后的結(jié)果做對(duì)比。
goos: darwin
goarch: amd64
pkg: example/string
cpu: Intel(R) Core(TM) i5-1038NG7 CPU @ 2.00GHz
BenchmarkConcatStrWithPlus-8 329544 87040 ns/op 663108 B/op 1 allocs/op
BenchmarkConcatStrWithSprintf-8 308691 160075 ns/op 1241769 B/op 4 allocs/op
PASS
ok example/string 78.604s
bytes.Buffer 和 strings.Builder
用法
bytes.Buffer 和 strings.Builder 底層類似,都是用一個(gè) []byte 類型的切片來(lái)存字符串。用法也類似,零值可以直接使用。
bytes.Buffer 拼接字符串:
var buf bytes.Buffer
// 拼接 "a" 和 "b"
buf.WriteString("a")
buf.WriteString("b")
str := buf.String() // str 等于 "ab"
strings.Builder 拼接字符串:
var sb strings.Builder
// 拼接 "a" 和 "b"
sb.WriteString("a")
sb.WriteString("b")
str := sb.String() // str 等于 "ab"
并且,兩者都提供了 Reset 方法,很方便結(jié)合 Sync.Pool 使用。
區(qū)別
需要注意的是,String() 方法實(shí)現(xiàn)還是有些許區(qū)別的,摘取 bytes.Buffer 的String方法的源碼注釋:
// String returns the contents of the unread portion of the buffer
// as a string. If the Buffer is a nil pointer, it returns "<nil>".
//
// To build strings more efficiently, see the strings.Builder type.
func (b *Buffer) String() string {
bytes.Buffer 的 String 方法會(huì)把底層 []byte 轉(zhuǎn)成字符串,這需要另外申請(qǐng)內(nèi)存,而 strings.Builder 則不用。
性能對(duì)比
// 使用 bytes.Buffer 拼接字符串
func BenchmarkConcatStrWithBuf(b *testing.B) {
var buf bytes.Buffer
for i := 0; i < b.N; i++ {
buf.WriteString("test")
}
_ = buf.String()
}
// 使用 strings.Builder 拼接字符串
func BenchmarkConcatStrWithSb(b *testing.B) {
var sb strings.Builder
for i := 0; i < b.N; i++ {
sb.WriteString("test")
}
_ = sb.String()
}
執(zhí)行: go test -bench . -benchmem ,得到以下結(jié)果:
BenchmarkConcatStrWithBuf-8 87914572 17.51 ns/op 16 B/op 0 allocs/op
BenchmarkConcatStrWithSb-8 278124620 9.562 ns/op 22 B/op 0 allocs/op
PASS
ok example/string 5.442s
對(duì)比上面的壓測(cè),strings.Builder(22 B/op)、bytes.Buffer(16 B/op) 比 Sprintf(1241769 B/op)和 + 號(hào)(663108 B/op)在內(nèi)存方面,差距還是很明顯的。
以上就是Go 庫(kù)bytes.Buffer和strings.Builder使用及性能對(duì)比的詳細(xì)內(nèi)容,更多關(guān)于Go bytes.Buffer對(duì)比strings.Builder的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
一文帶你了解Go中跟蹤函數(shù)調(diào)用鏈的實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了go如何實(shí)現(xiàn)一個(gè)自動(dòng)注入跟蹤代碼,并輸出有層次感的函數(shù)調(diào)用鏈跟蹤命令行工具,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-11-11
golang給函數(shù)參數(shù)設(shè)置默認(rèn)值的幾種方式小結(jié)(函數(shù)參數(shù)默認(rèn)值
在日常開(kāi)發(fā)中我們有時(shí)候需要使用默認(rèn)設(shè)置,下面這篇文章主要給大家介紹了關(guān)于golang給函數(shù)參數(shù)設(shè)置默認(rèn)值的幾種方式小結(jié)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01
golang 獲取當(dāng)前執(zhí)行程序路徑的操作
這篇文章主要介紹了golang 獲取當(dāng)前程序執(zhí)行路徑的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12
go語(yǔ)言使用pipe讀取子進(jìn)程標(biāo)準(zhǔn)輸出的方法
這篇文章主要介紹了go語(yǔ)言使用pipe讀取子進(jìn)程標(biāo)準(zhǔn)輸出的方法,實(shí)例分析了Go語(yǔ)言針對(duì)進(jìn)程操作的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03
一文帶你探索Go語(yǔ)言中crypto/md5標(biāo)準(zhǔn)庫(kù)的強(qiáng)大功能
我們將從MD5算法的基礎(chǔ)知識(shí)入手,逐步深入到如何在Go中有效使用crypto/md5標(biāo)準(zhǔn)庫(kù),包括基本的使用方法、實(shí)際應(yīng)用案例分析,以及性能和安全性的考量,需要的可以參考下2024-02-02

