浅析Golang中字符串拼接问题

目录
  • 1.概述
  • 2.Golang中字符串拼接的方式
  • 3.总结

1.概述

Go的字符串是一个不可改变的数据结构,这和其他语言如JAVA,C++等的设定很类似.总体来说,有如下五种拼接方式,下面我们将论述各种方式的性能问题,以及如何选择.

(golang字符串,内存模型)

type StringHeader struct {
	Data uintptr
	Len  int
}

注意:字符串具有不可改变的特性,即便通过指针等变相操作

	var a string = "old"
	bptr := (*reflect.StringHeader)(unsafe.Pointer(&a))
	dataPtr := (*byte)(unsafe.Pointer(bptr.Data))
	var b = [3]byte{'n', 'e', 'w'}
	*dataPtr = b[0] //报错
	fmt.Println(bptr)

2.Golang中字符串拼接的方式

方式一、直接+

当使用连接符 + 拼接两个字符串时,会生成一个新的字符串并开辟新的内存空间,空间大小等于两个字符串之和。在训中中时,不断拼接新的字符串,这样就会不断申请内存空间, 性能就会越来越差。 所以,在字符串密集拼接场景中,使用 + 会严重降低性能。包括热路径的代码.

方式二、strings.Builder

func Benchmark_StringsBuilder(b *testing.B) {
	var sb strings.Builder
	for i := 0; i < b.N; i++ {
		sb.WriteString("hello world")
	}
	_ = sb.String()
}

方式三、bytes.Buffer

func Benchmark_BytesBuffer(b *testing.B) {
	var buf bytes.Buffer
	for i := 0; i < b.N; i++ {
		buf.WriteString("hello world")
	}
	_ = buf.String()
}

方式四、fmt.Fprint(&buf,&str)

方式五、strings.Join

性能不是最优,但在切片的情况下,可以用来拼接

3.总结

Benchmark_StringAdd Benchmark_StringAdd-8 117806 127059 ns/op Benchmark_BytesBuffer Benchmark_BytesBuffer-8 38938282 25.88 ns/op Benchmark_StringsBuilder Benchmark_StringsBuilder-8 57249450 18.53 ns/op

3.1 性能方面,strings.Builder 比 bytes.Buffer 快差不多 20%,

原因:strings.Builder 和 bytes.Buffer 底层都是一个 []byte,但是 bytes.Buffer 转换字符串时会重新申请内存空间用来存放, 而 strings.Builder 直接将底层的 []byte 利用指针的方式强转为字符串.

//strings.Builder的String()
func (b *Builder) String() string {
    return *(*string)(unsafe.Pointer(&b.buf))
}

//bytes.Builder的String()
func (b *Buffer) String() string {
    if b == nil {
        // Special case, useful in debugging.
        return "<nil>"
    }
    return string(b.buf[b.off:])
}

3.2 strings.Builder通常性能最优,但底层依赖于[]byte,所以如果平凡扩容就不妙了,因此我们需要借助它的Grow方法,以已分配最终[]byte的容量,避免因为扩容带来的性能损失

func Benchmark_StringConcat(b *testing.B) {
    str := "hello world"
    var sb strings.Builder
    sb.Grow(b.N * len(str))
    for i := 0; i < b.N; i++ {
        sb.WriteString(str)
    }
    _ = sb.String()
}

3.3 strings.Builder没有拷贝构造(借用C++说法),因为

type Builder struct {
addr *Builder // of receiver, to detect copies by value
buf []byte  //如果拷贝,这个buf共享,最后导致数据混乱
}

到此这篇关于浅析Golang中字符串拼接问题的文章就介绍到这了,更多相关Golang字符串拼接内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • go语言中五种字符串的拼接方式(小结)

    目录 +拼接方式 sprintf函数 Join函数 buffer.Builderbuffer.WriteString函数 buffer.Builder函数 ps:直接使用运算符 主要结论 +拼接方式 这种方式是我在写golang经常用的方式,go语言用+拼接,php使用.拼接,不过由于golang中的字符串是不可变的类型,因此用 + 连接会产生一个新的字符串对效率有影响. func main() { s1 := "hello" s2 := "word" s3 :=

  • Golong字符串拼接性能优化及原理介绍

    目录 1.字符串高效拼接 1.1 常见的字符串拼接 1.2 字符串拼接测试 1.3 推荐 2.相关原理 2.1 + 号 2.2 strings.Builder 与 bytes.Buffer 2.2.1 内部[]byte 增长方式: 2.2.2 性能比较 1.字符串高效拼接 go 字符串是不可修改的,所谓字符串拼接就是创建新的字符串对象.如果代码中存在大量的字符串拼接,那么性能将会存在影响. 1.1 常见的字符串拼接 +号 func plusConcat(n int, s string) stri

  • go语言字符串的拼接和切片方法总结

    目录 一,go字符串的本质 二,字符串拼接的几种方法 1,使用+号拼接字符串 2,使用fmt包的Sprintf()函数 3,使用strings包的Join()函数 4,使用bytes.Buffer储存字符串再打印输出 三,字符串的切片 四,字符串函数 附:golang将整型切片转换为字符串 总结 一,go字符串的本质 go语言字符串的本质就是byte[]数组,里面每一个数据存的是字符的Unicode码. 二,字符串拼接的几种方法 1,使用+号拼接字符串 拼接之后返回一个新的字符串. packag

  • Golang语言如何高效拼接字符串详解

    目录 01.介绍 02.操作符 + 03.strings.Join 方法 04.fmt.Sprint 方法 05.bytes.Buffer 类型 06.strings.Builder 类型 07.总结 01.介绍 在编程语言中,字符串是一种重要的数据结构.在 Golang 语言中,因为字符串只能被访问,不能被修改,所以,如果我们在 Golang 语言中进行字符串拼接操作,Golang 需要进行内存拷贝. 如果读者朋友们了解过 Golang 语言内存管理的相关知识,就会知道内存拷贝会带来性能消耗.

  • Golang字符串的拼接方法汇总

    字符串拼接在 golang 里面其实有很多种实现. 实现方式 直接使用运算符 func BenchmarkAddStringWithOperator(b *testing.B) {     hello := "hello"     world := "world"     for i := 0; i < b.N; i++ {         _ = hello + "," + world     } } golang里面的字符串都是不可变的

  • Go语言中的字符串拼接方法详情

    目录 1.string类型 2.strings包 2.1 strings.Builder类型 2.2 strings.Reader类型 3.bytes.Buffer 3.1 bytes.Buffer:写数据 3.2 bytes.Buffer:读数据 4.字符串拼接 4.1 直接相加 4.2strings.Builder 4.3 strings.Join() 4.4 bytes.Buffer 4.5 append方法 4.6 fmt.Sprintf 5.字符串拼接性能测试 1.string类型 s

  • 浅析Golang中字符串拼接问题

    目录 1.概述 2.Golang中字符串拼接的方式 3.总结 1.概述 Go的字符串是一个不可改变的数据结构,这和其他语言如JAVA,C++等的设定很类似.总体来说,有如下五种拼接方式,下面我们将论述各种方式的性能问题,以及如何选择. (golang字符串,内存模型) type StringHeader struct { Data uintptr Len int } 注意:字符串具有不可改变的特性,即便通过指针等变相操作 var a string = "old" bptr := (*r

  • 浅析Python中字符串的intern机制

    intern机制: 字符串类型作为Python中最常用的数据类型之一,Python解释器为了提高字符串使用的效率和使用性能,做了很多优化,例如:Python解释器中使用了 intern(字符串驻留)的技术来提高字符串效率,什么是intern机制?即值同样的字符串对象仅仅会保存一份,放在一个字符串储蓄池中,是共用的,当然,肯定不能改变,这也决定了字符串必须是不可变对象. 简单原理: 实现 Intern 机制的方式非常简单,就是通过维护一个字符串储蓄池,这个池子是一个字典结构,如果字符串已经存在于池

  • Java 8中字符串拼接新姿势StringJoiner详解

    在为什么阿里巴巴不建议在for循环中使用"+"进行字符串拼接一文中,我们介绍了几种Java中字符串拼接的方式,以及优缺点.其中还有一个重要的拼接方式我没有介绍,那就是Java 8中提供的StringJoiner ,本文就来介绍一下这个字符串拼接的新兵. 如果你想知道一共有多少种方法可以进行字符串拼接,教你一个简单的办法,在Intellij IDEA中,定义一个Java Bean,然后尝试使用快捷键自动生成一个toString方法,IDEA会提示多种toString生成策略可供选择. 1

  • Python 中字符串拼接的多种方法

    python拼接字符串一般有以下几种方法: ①直接通过(+)操作符拼接 s = 'Hello'+' '+'World'+'!' print(s) 输出结果: Hello World! 使用这种方式进行字符串连接的操作效率低下,因为python中使用 + 拼接两个字符串时会生成一个新的字符串,生成新的字符串就需要重新申请内存,当拼接字符串较多时自然会影响效率. ②通过str.join()方法拼接 strlist=['Hello',' ','World','!'] print(''.join(str

  • golang中字符串MD5生成方式总结

    方案一 func md5V(str string) string { h := md5.New() h.Write([]byte(str)) return hex.EncodeToString(h.Sum(nil)) } 方案二 func md5V2(str string) string { data := []byte(str) has := md5.Sum(data) md5str := fmt.Sprintf("%x", has) return md5str } 方案三 func

  • Golang中字符串(string)与字节数组([]byte)一行代码互转实例

    目录 一.字符串与字节数组? 二.详细代码 1.简单的方式字节转字符串 2.简单的字符串转字节数组 3.字节转字符串 4.字符串转字节数组 5.完整运行测试 补充:一些结论如下 总结 一.字符串与字节数组? 字符串是 Go 语言中最常用的基础数据类型之一,本质上是只读的字符型数组,虽然字符串往往都被看做是一个整体,但是实际上字符串是一片连续的内存空间. Go 语言中另外一个类型字节(Byte).在ASCII中,一个英文字母占一个字节的空间,一个中文汉字占两个字节的空间.英文标点占一个字节,中文标

  • 浅析Golang中的内存逃逸

    目录 什么是内存逃逸分析 为什么需要逃逸分析 如果变量放错了位置会怎样 内存逃逸场景 return 局部变量的指针 interface{} 动态类型 栈空间不足 闭包 性能 最后 什么是内存逃逸分析 内存逃逸分析是go的编译器在编译期间,根据变量的类型和作用域,确定变量是堆上还是栈上 简单说就是编译器在编译期间,对代码进行分析,确定变量分配内存的位置.如果变量需要分配在堆上,则称作内存逃逸了. 为什么需要逃逸分析 因为go语言是自动自动内存管理的,也就是有GC的.开发者在写代码的时候不需要关心考

  • 详解Golang中字符串的使用

    目录 1.字符串编码 2.字符串遍历 3.字符串中的字符数 4.字符串trim 5.字符串连接 6.字节切片转字符串 1.字符串编码 在go中rune是一个unicode编码点. 我们都知道UTF-8将字符编码为1-4个字节,比如我们常用的汉字,UTF-8编码为3个字节.所以rune也是int32的别名. type rune = int32 当我们打印一个英文字符hello的时候,我们可以得到s的长度为5,因为英文字母代表1个字节: package main import "fmt"

  • javascript中字符串拼接需注意的问题

    在开发中大家也都会注意尽量使用StringBuilder而不采用普通的字符串拼接方式.但是可能大部分开发者却忽略了js中也需要注意这种效率问题. 下面进行一项性能测试,用事实来说话! 复制代码 代码如下: function xntest(){ var d1=new Date(); var str=""; for(var i=0;i<10000;i++){ str+="stext"; } var d2=new Date(); document.write(&qu

  • javascript中字符串拼接详解

    最近在研究<javascript高级程序设计>中,有一段关于字符串特点的描述,原文大概如下:ECMAScript中的字符串是不可变的,也就是说,字符串一旦创建,他们的值就不能改变.要改变某个变量的保存的的字符串,首先要销毁原来的字符串,然后再用另外一个包含新值的字符串填充该变量,例如: 复制代码 代码如下: var lang = "Java"; lang = lang + "Script"; 实现这个操作的过程如下:首先创建一个能容纳10个字符的新字符串

随机推荐