日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Go?庫bytes.Buffer和strings.Builder使用及性能對比_Golang

作者:小馬別過河 ? 更新時間: 2023-01-14 編程語言

前言

字符串拼接是老生常談了。在 Go 語言中,常見的拼接字符串的方法有:用+號,或者使用fmt包的Sprintf

str1 := "a" + "b" // str1: "ab"
str2 := fmt.Sprintf("%s%s", "a", "b") // str2: "ab"

字符串低層是不可修改的,所以每次拼接字符串,都需要重新分配內存。如果需要頻繁拼接字符串,上面兩種方法可能性能低下。我們寫下壓測代碼

// 使用 + 拼接字符串
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")
	}
}

執行: go test -bench . -benchmem ,得到以下結果。這個壓測結果,留著跟下文的優化后的結果做對比。

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 底層類似,都是用一個 []byte 類型的切片來存字符串。用法也類似,零值可以直接使用。

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 方法,很方便結合 Sync.Pool 使用。

區別

需要注意的是,String() 方法實現還是有些許區別的,摘取 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 方法會把底層 []byte 轉成字符串,這需要另外申請內存,而 strings.Builder 則不用。

性能對比

// 使用 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()
}

執行: go test -bench . -benchmem ,得到以下結果:

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

對比上面的壓測,strings.Builder(22 B/op)、bytes.Buffer(16 B/op) 比 Sprintf(1241769 B/op)和 + 號(663108 B/op)在內存方面,差距還是很明顯的。

原文鏈接:https://juejin.cn/post/7168765782082453535

欄目分類
最近更新