• Ukieweb

    佳的博客

    曾梦想仗剑天涯,后来工作忙没去。

Golang 字符串拼接方法汇总以及builder优化

拼接方法有:

  • +号拼接

  • fmt拼接

  • Join拼接

  • buffer拼接

  • builder拼接

在少数据的情况下,这几个方法相差不大,但是当要拼接的字符串很大的时候,推荐使用 builder。而+号连接适用于短小的,常量字符串的拼接,因为编译器会优化

+号拼接

s := s1+s2+s3

fmt拼接

s := fmt.Sprintf("%v%v",s1,s2)

Join拼接

接收一个字符串数组,转换为一个拼接好的字符串

sList := []string{s1,s2}

s := strings.Join(SList,"")

buffer拼接

不止可以拼接字符串,还可以拼接byte等

var b = bytes.Buffer

b.WriteString(s1)
b.WriteString(S2)

s := b.String()

builder拼接

var b strings.Builder

b.WriteString(s1)
b.WriteString(s2)

s := b.String()

对 builder 进行测试

project\stringBuilder\sb.go

package stringBuilder

import "strings"

func StringBuilder(p []string) string {
	var b strings.Builder
	l:=len(p)
	for i:=0;i<l;i++{
		b.WriteString(p[i])
	}
	return b.String()
}

project\stringBuilder\sb_test.go

package stringBuilder
import "testing"
const TESTSTRING  = "test,"
/*
	初始化函数
	生成一个具有N个字符串的数组
*/
func initStrings(N int) []string{
	s:=make([]string,N)
	for i:=0;i<N;i++{
		s[i]=TESTSTRING
	}
	return s;
}
/*
	测试
	10个字符串
*/
func BenchmarkStringBuilder10(b *testing.B) {
	p:= initStrings(10)
	b.ResetTimer()
	for i:=0;i<b.N;i++{
		StringBuilder(p)
	}
}


/*
	测试
	100个字符串
*/

func BenchmarkStringBuilder100(b *testing.B) {
	p:= initStrings(100)
	b.ResetTimer()
	for i:=0;i<b.N;i++{
		StringBuilder(p)
	}
}

/*
	测试
	1000个字符串
*/

func BenchmarkStringBuilder1000(b *testing.B) {
	p:= initStrings(1000)
	b.ResetTimer()
	for i:=0;i<b.N;i++{
		StringBuilder(p)
	}
}

测试结果

goos: windows
goarch: amd64
pkg: TestProject/stringBuilder
BenchmarkStringBuilder10-4   5163981    228 ns/op      120 B/op       4 allocs/op
BenchmarkStringBuilder100-4  1000000    1150 ns/op     1016 B/op      7 allocs/op
BenchmarkStringBuilder1000-4 107428     11735 ns/op    21240 B/op     13 allocs/op

PASS

从基准测试结果可以看出,主要是慢在了多次内存分配上,如果多次内存分配而且引起GC的话,就会更慢!

简单来说,就是通过append函数向[]byte b中填充,当b字节数组扩容时,就会引起内存分配,从而使得操作变慢。

对 builder 进行优化

减少内存分配次数,也就是预先给b字节数组分配大小cap

func StringBuilder(p []string,cap int) string {
	var b strings.Builder
	l:=len(p)
	b.Grow(cap)
	for i:=0;i<l;i++{
		b.WriteString(p[i])
	}
	return b.String()
}

测试代码

//测试代码以10个字符串为例
//修改为如下
func BenchmarkStringBuilder10(b *testing.B) {
	p:= initStrings(10)
	b.ResetTimer()
	cap := 10*len(TESTSTRING)
	for i:=0;i<b.N;i++{
		StringBuilder(p,cap)
	}
}

测试结果

BenchmarkStringBuilder10-4   10027047    114 ns/op    64 B/op    1 allocs/op
BenchmarkStringBuilder100-4  1312066     810 ns/op    512 B/op   1 allocs/op
BenchmarkStringBuilder1000-4  141570     8080 ns/op   5376 B/op   1 allocs/op
PASS

能优化20%~50%


0
0
下一篇:Golang 种 读/写 文件的几种常用方法

0 条评论

老佳啊

85后,大专学历,中原人士,家里没矿。

由于年轻时长的比较帅气,导致在别人眼里,我一直不谈恋爱的原因是清高,实则是自己的小自卑。最大的人生目标就是找一个相知相爱相容的人,共度余生。

和人相处时如果能感受到真诚,会非常注重彼此的关系,对别人没有什么心机,即使有利益冲突,一般也会以和为贵,因为在这个世界上,物质的东西,从来不会吸引到我。

特别迷恋那些大山大水,如果现在还能隐居,可能早就去了。对那些宏伟的有底蕴的人文景观比较不感冒。

从事于IT行业,却一直对厨房念念不忘,由于身材魁梧,总觉得自己上辈子是个将军,可惜这辈子没当兵,也不会打架。