浅析Golang中字符串拼接问题
作者:落风雪 发布时间:2024-04-28 09:17:07
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共享,最后导致数据混乱
}
来源:https://juejin.cn/post/7199903805509124151


猜你喜欢
- 绘制动图FuncAnimation,它的使用要求简洁且定制化程度较高。如果想将很多图片合并为一个动图,那么ArtistAnimation是最
- 在ASP与ASP.NET之间共享对话状态(1)ASP实现原来的ASP对话只能将对话数据保存在内存中。为了将对话数据保存到SQL Server
- 在本教程中使用MySQL最新的MySQL服务8.0.11的社区绿色版本进行安装,绿色版为zip格式的包,安装分为以下四步走:第一步:下载My
- 近几天闲着没事开始学了些python,看了看之前写过的代码,把写过的基础的几个程序写进博客,今天是第一个。一个可以说简单的不能再简单的小程序
- 在开始部分,请看官非常非常耐心地阅读下面几个枯燥的术语解释,本来这不符合本教程的风格,但是,请看官谅解,因为列位将来一定要阅读枯燥的东西的。
- 1、配置pycharm 依次点击"File"-->"Settings",进入"Edi
- 这篇文章主要介绍了Python实现自定义读写分离代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- 一个图形化的交互式运行环境,对于编程语言的学习和开发,特别是可视化方面,提供了极大的便利。比如在window上使用R语言进行绘图,在R语言自
- 用python实现的一个井字棋游戏,供大家参考,具体内容如下#Tic-Tac-Toe 井字棋游戏#全局常量X="X"O=
- 此文仅当学习笔记用.这个实例是在Python环境下如何爬取弹出窗口的内容,有些时候我们要在页面中通过点击,然后在弹出窗口中才有我们要的信息,
- 在使用opencv显示图像时,有时候需要显示多张图像,就会出现多个窗口,显得冗余,用户不好操作。这时候就想着能不能将这些图像在一个窗口中显示
- 工具版本python版本:3.8 django版本:2.0.0 mysql版本: 5.5.53 pip3创建工程djangostartDja
- 前言在Vue3响应式对象是如何实现的(1)中,我们已经从功能上实现了一个响应式对象。如果仅仅满足于功能实现,我们就可以止步于此了。但在上篇中
- 很多人说设计是力求细节的,在网页设计里表达出的细节就是图标。图标在一个设计里带来了额外的注解并且使设计里的对象和元素引起用户的注意。以下介绍
- 目的:本文实现QT登录界面,输入账号和密码后,系统连接Oracle数据进行判断账号和密码(MD5加密)是否和数据库一致,如果一致则提示登录成
- 对于字典,通过“键”获得“值”非常简单,但通过“值”获得“键”则需绕些弯子。一、通用:自行定义函数方式假设:输入:一个字典(dic)+要找的
- 前言在前几篇博客中,分别就棋子的颜色识别、模板匹配等定位方式进行了介绍和实践,这一篇博客就来验证一下github中最热门的跳一跳 * 中采用的
- Python将控制台输出另存为日志文件需求  在 PyCharm 中或者说运行 python 程序时会使
- 最近在学习python,之前一直用notepad++作为编辑器,偶然发现了VScode便被它的颜值吸引。用过之后发现它启动快速,插件丰富,下
- 1.单继承父类也叫基类子类也叫派生类如下所示,继承的关系:继承的书写格式:class 子类(父类):方法实例:class Animal: &