geektutu / blog

极客兔兔的博客,Coding Coding 创建有趣的开源项目。
https://geektutu.com
Apache License 2.0
166 stars 21 forks source link

字符串拼接性能及原理 | Go 语言高性能编程 | 极客兔兔 #107

Open geektutu opened 3 years ago

geektutu commented 3 years ago

https://geektutu.com/post/hpg-string-concat.html

Go 语言/golang 高性能编程,Go 语言进阶教程,Go 语言高性能编程(high performance go)。详细介绍了构造字符串/拼接字符串(string concatation) 的 5 种方式:+, strings.Builder, bytes.Buffer, []byte 和 fmt.Sprintf,比较了这 5 种方式的性能,并且深入解释了背后的原理。

sh1luo commented 3 years ago
if cap > doublecap {
        newcap = cap
    } else {
        if old.len < 1024 {
            newcap = doublecap
        } else {
            // Check 0 < newcap to detect overflow
            // and prevent an infinite loop.
            for 0 < newcap && newcap < cap {
                newcap += newcap / 4
            }
            // Set newcap to the requested cap when
            // the newcap calculation overflowed.
            if newcap <= 0 {
                newcap = cap
            }
        }
    }

源码里貌似写的是大于1024后不一致呀,博主的golang版本是什么呢?

geektutu commented 3 years ago

@sh1luo ,假设 old.len == 1000,此时 cap == 1024,那么 newcap = doublecap 将会是 2048,所以 1024 到 2048 也是倍数增加的,和 benchmark 跑出来的数字对应。

l-xue-yu commented 3 years ago

写的不错,详略得当,有理有据。好好和大佬学习。

geektutu commented 3 years ago

@l-xue-yu 笔芯~ 😸

c-jf commented 3 years ago

使用strings.Builder的话,每箱拼接一个字符串都要调用一下builder.WriteString,感觉好麻烦啊

callmePicacho commented 3 years ago

总结:

  1. 字符串最高效的拼接方式是结合预分配内存方式 Grow 使用 string.Builder
  2. 当使用 + 拼接字符串时,生成新字符串,需要开辟新的空间
  3. 当使用 strings.Builderbytes.Buffer[]byte 的内存是按倍数申请的,在原基础上不断增加
  4. strings.Builderbytes.Buffer 性能更快,一个重要区别在于 bytes.Buffer 转化为字符串重新申请了一块空间存放生成的字符串变量;而 strings.Builder 直接将底层的 []byte 转换成字符串类型返回
wathenjiang commented 3 years ago

本质上 string.Builder 是以空间换时间,如果不进行字符串的拼接,那么 string.Builder 这种非紧凑型设计有内存碎片,而 string 本身是不会有内存碎片(不考虑 CPU 的内存对齐)。

geektutu commented 3 years ago

@Spongecaptain string.Builder 是为了字符串的多次拼接设计的,这样的话,按照算法申请空间,可以尽量避免空间不够导致的拷贝。如果是一次拼接,甚至是不拼接,那用 string 就 OK 了。

hcf1425 commented 2 years ago

BenchmarkPlusConcat 16801 71512 ns/op 0 B/op 0 allocs/op 为什么我的内存分配次数是零呢?我在Linux和mac上都分别跑了一下,-benchmem都是0.