手记

寻找golang中最高效的字符串连接函数


以下五个字符串连接函数,你认为哪一个最快?

func StrConcat1(strs []string) (string) {

    var str string

    for _, value := range strs {

        str += value

    }

    return str

}

func StrConcat2(strs []string) (string) {

    if len(strs) == 0 {

        return ""

    }

    b := bytes.Buffer{}

    for _, s := range strs {

        b.WriteString(s)

    }

    return b.String()

}

func StrConcat3(strs []string) (string) {

    return strings.Join(strs, "")

}

func StrConcat4(strs []string) (string) {

    var data []byte

    for _, value := range strs {

        data = append(data, value...)

    }

    return string(data)

}

func StrConcat5(strs []string) (string) {

    var length int

    for _, s := range strs {

        length += len(s)

    }

    bs := make([]byte, length)

    var i int

    for _, value := range strs {

        i += copy(bs[i:], value)

    }

    return string(bs[:])

}

编写如下的测试文件

import "testing"

var TestStr = []string{"hello", "world", "my", "god", "this", "is", "big", "content"}

func Benchmark_StrConcat1(b *testing.B)  {

    for i := 0; i < b.N ; i++ {

        StrConcat1(TestStr)

    }

}

func Benchmark_StrConcat2(b *testing.B)  {

    for i := 0; i < b.N ; i++ {

        StrConcat2(TestStr)

    }

}

func Benchmark_StrConcat3(b *testing.B)  {

    for i := 0; i < b.N ; i++ {

        StrConcat3(TestStr)

    }

}

func Benchmark_StrConcat4(b *testing.B)  {

    for i := 0; i < b.N ; i++ {

        StrConcat4(TestStr)

    }

}

func Benchmark_StrConcat5(b *testing.B)  {

    for i := 0; i < b.N ; i++ {

        StrConcat5(TestStr)

    }

}

然后执行测试命令

go test -test.bench=".*"

执行结果如下:

Benchmark_StrConcat1-4       5000000           366 ns/op

Benchmark_StrConcat2-4      10000000           178 ns/op

Benchmark_StrConcat3-4      10000000           127 ns/op

Benchmark_StrConcat4-4      10000000           178 ns/op

Benchmark_StrConcat5-4      20000000           102 ns/op

可见,第5个函数的效率是最高的,虽然它的代码量最多。

其次是第3个函数,其实我们查看第3个函数的源代码就可以发现,它与第5个函数本质上是一样的,但是因为多了对分隔符的拷贝操作,执行时间增加了。我认为这个系统函数可以再优化,判断分隔符是不是空的,如果是空的,就按第5个函数那个处理,这样效率还能提升15%。

附,strings.Join函数源代码:

// Join concatenates the elements of a to create a single string. The separator string

// sep is placed between elements in the resulting string.

func Join(a []string, sep string) string {

    switch len(a) {

    case 0:

        return ""

    case 1:

        return a[0]

    case 2:

        // Special case for common small values.

        // Remove if golang.org/issue/6714 is fixed

        return a[0] + sep + a[1]

    case 3:

        // Special case for common small values.

        // Remove if golang.org/issue/6714 is fixed

        return a[0] + sep + a[1] + sep + a[2]

    }

    n := len(sep) * (len(a) - 1)

    for i := 0; i < len(a); i++ {

        n += len(a[i])

    }

    b := make([]byte, n)

    bp := copy(b, a[0])

    for _, s := range a[1:] {

        bp += copy(b[bp:], sep)

        bp += copy(b[bp:], s)

    }

    return string(b)

}

©著作权归作者所有:来自51CTO博客作者ustb80的原创作品,如需转载,请注明出处,否则将追究法律责任


0人推荐
随时随地看视频
慕课网APP