zoukankan      html  css  js  c++  java
  • Golang 字符串拼接及builder优化

    Overview

    • +号拼接
    • 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 := String() 
    

    builder拼接

    var b strings.Builder
    b.WriteString(s1)
    b.WriteString(s2)
    s := b.String()
    

    对builder进行优化

    测试代码

    projectstringBuildersb.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()
    }
    
    
    

    projectstringBuildersb_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
    
    

    builder慢在哪了?

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

    builder 源码

    // WriteString appends the contents of s to b's buffer.
    // It returns the length of s and a nil error.
    func (b *Builder) WriteString(s string) (int, error) {
    	b.copyCheck()
    	b.buf = append(b.buf, s...)
    	return len(s), nil
    }
    

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

    解决办法

    减少内存分配次数,也就是预先给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%

  • 相关阅读:
    idea问题
    队列的实现
    sqlalchemy 连接mysql8.0报 RuntimeError: cryptograpy si requeired for sha256_password 错误
    ubunut18.04 下安装 gitlab ce版,使用清华源
    在Centos下单机部署kubernetes
    在Centos 7.7下用minikube部署单节点kubernetes.
    访问docker desktop创建的Hyper-v虚拟机DockerDesktopVM
    为kubernetes-dashboard页面增加过期时间,减少登录次数.
    为Docker Desktop安装kubernet-dashboard
    用Hyper-v 在win10下使用Docker-Desktop体验kubernetes
  • 原文地址:https://www.cnblogs.com/Jun10ng/p/12682524.html
Copyright © 2011-2022 走看看