• 【原】golang 中字符串拼接的方式性能对比


    背景

        开发过程中,常常会用到字符串拼接完成某种需求,我们能马上想到的解决办法有+,fmt.Sprintf,高级一点可能还会想到strings包的Join 方法,甚至想到bytes.buffer,再用writeString 方法完成,再而想到strings.builder。但究竟哪种效率高呢?我们在使用过程中如何选择?只有实测才知道

    结论

        测试结论 bytes.Buffer > + > strings.Join > strings.builder > fmt.Sprintf 。

        简单拼接用+,复杂,追求高效用bytes.Buffer

    实测

        以下测试在个人mac 系统下。go 版本1.15,不同版本可能略有不同,以自己实际输出为准。

    测试1

     

    package strings

    import (
    "bytes"
    "fmt"
    "strings"
    "testing"
    )

    func BenchmarkStringBuild(b *testing.B) {
    hello := "hello"
    world := "world"
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
    var result strings.Builder
    result.WriteString(hello)
    result.WriteString(world)
    //result.WriteString("aaa")
    //result.WriteString(strconv.Itoa(10000))
    }
    }

    func BenchmarkStringJia(b *testing.B) {
    hello := "hello"
    world := "world"
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
    //_ = hello + world + "aaa !" + strconv.Itoa(10000)
    _ = hello + world
    }
    }

    func BenchmarkStringSprintf(b *testing.B) {
    hello := "hello"
    world := "world"
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
    //_ = fmt.Sprintf("%s,%s,%s,%d", hello, world, "aaa !", 1000)
    _ = fmt.Sprintf("%s,%s", hello, world)
    }
    }

    func BenchmarkAddStringWithJoin(b *testing.B) {
    hello := "hello"
    world := "world"
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
    //_ = strings.Join([]string{hello, world, "aaa !", strconv.Itoa(10000)}, ",")
    _ = strings.Join([]string{hello, world}, ",")
    }
    }

    func BenchmarkAddStringWithBuffer(b *testing.B) {
    hello := "hello"
    world := "world"
    for i := 0; i < 1000; i++ {
    var buffer bytes.Buffer
    buffer.WriteString(hello)
    buffer.WriteString(",")
    buffer.WriteString(world)
    //buffer.WriteString("aaa !")
    //buffer.WriteString(strconv.Itoa(10000))
    _ = buffer.String()
    }
    }

     

     

    测试2

     

     

    package strings

    import (
    "bytes"
    "fmt"
    "strconv"
    "strings"
    "testing"
    )

    func BenchmarkStringBuild(b *testing.B) {
    hello := "hello"
    world := "world"
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
    var result strings.Builder
    result.WriteString(hello)
    result.WriteString(world)
    result.WriteString("aaa")
    result.WriteString(strconv.Itoa(10000))
    }
    }

    func BenchmarkStringJia(b *testing.B) {
    hello := "hello"
    world := "world"
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
    _ = hello + world + "aaa !" + strconv.Itoa(10000)
    //_ = hello + world
    }
    }

    func BenchmarkStringSprintf(b *testing.B) {
    hello := "hello"
    world := "world"
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
    _ = fmt.Sprintf("%s,%s,%s,%d", hello, world, "aaa !", 1000)
    //_ = fmt.Sprintf("%s,%s", hello, world)
    }
    }

    func BenchmarkAddStringWithJoin(b *testing.B) {
    hello := "hello"
    world := "world"
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
    _ = strings.Join([]string{hello, world, "aaa !", strconv.Itoa(10000)}, ",")
    //_ = strings.Join([]string{hello, world}, ",")
    }
    }

    func BenchmarkAddStringWithBuffer(b *testing.B) {
    hello := "hello"
    world := "world"
    for i := 0; i < 1000; i++ {
    var buffer bytes.Buffer
    buffer.WriteString(hello)
    buffer.WriteString(",")
    buffer.WriteString(world)
    buffer.WriteString("aaa !")
    buffer.WriteString(strconv.Itoa(10000))
    _ = buffer.String()
    }
    }

     

     

    执行:$ go test -bench=. -benchmem -run=none

    结果显而易见,即便我只拼接hello world,不同方式的对比差异也是显著的。

    可看到

    • string.Builder内存分配4次,分配字节数64字节
    • + 进行内存分配1次,分配字节数5字节
    • fmt.Sprintf 进行内存分配3次,分配字节数64字节
    • strings.Join 进行内存分配2次,分配字节数37字节
    • bytes.Buffer WriteString进行内存分配0次,分配字节数0

    结果一般没想到的是+ 在1.15版本性能是大于 strings.Join 和fmt.Sprintf的。所以在我们使用中优先选择bytes.Buffer WriteString、其次简单的,方便阅读和编写可用+。

  • 相关阅读:
    【转载】这是炎热小镇慵懒的一天
    【原创】Google的文本内容对比代码
    【原创】你知道Oracle 10G能存多少数据吗
    【原创】一个亿级数据库优化过程
    【原创】关于not in的一些事情
    【原创】自动结束进程脚本
    Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等
    Android 解决ListView 和 ScrollView 共存冲突的问题
    使用Symfony2的组件创建自己的PHP框架
    数据管理 ListView SQLite Dialog
  • 原文地址:https://www.cnblogs.com/already/p/13686154.html
Copyright © 2020-2023  润新知