美文网首页
go 基准测试

go 基准测试

作者: wayyyy | 来源:发表于2022-01-08 22:07 被阅读0次

    基准测试主要用于评估代码的性能,Go 语言测试框架可以让我们很容易地进行基准测试,同样需要遵循四点规则:

    1. 基准测试函数必须以 Benchmark 开头,函数的签名必须接收一个指向 testing.B 类型的指针,并且不能返回任何值。
      func BenchmarkStringPlus100(b *testing.B) {
        // ...
      }
      
    2. 最后的 for 循环很重要,被测试的代码要放到循环里,b.N 是基准测试框架提供的,表示循环的次数,因为需要反复调用测试的代码,才可以评估性能。
      for i := 0; i < b.N; i++ {
          stringBuilder(p)
      }
      

    下面展示一个例子测试不同方法的字符串拼接效率。

    • stringcat.go
      package main
      
      import (
          "bytes"
          "fmt"
          "strings"
      )
      
      const BLOG = "http://www.baidu.org/"
      
      func initStrings(N int) []string {
          s := make([]string, N)
          for i := 0; i < N; i++ {
              s[i] = BLOG
          }
          return s
      }
      
      func initStringi(N int) []interface{} {
          s := make([]interface{}, N)
          for i := 0; i < N; i++ {
              s[i] = BLOG
          }
          return s
      }
      
      func stringPlus(p []string) string {
          var s string
          l := len(p)
          for i := 0; i < l; i++ {
              s += p[i]
          }
          return s
      }
      
      func stringFmt(p []interface{}) string {
          return fmt.Sprint(p...)
      }
      
      func stringJoin(p []string) string {
          return strings.Join(p, "")
      }
      
      func stringBuffer(p []string) string {
          var b bytes.Buffer
          l := len(p)
          for i := 0; i < l; i++ {
              b.WriteString(p[i])
          }
          return b.String()
      }
      
      func stringBuilder(p []string) string {
          var b strings.Builder
          l := len(p)
          for i := 0; i < l; i++ {
              b.WriteString(p[i])
          }
          return b.String()
      }
      
    • stringcat_test.go
      package main
      
      import "testing"
      
      func BenchmarkStringPlus100(b *testing.B) {
          p := initStrings(100)
          b.ResetTimer()
          for i := 0; i < b.N; i++ {
              stringPlus(p)
          }
      }
      
      func BenchmarkStringFmt100(b *testing.B) {
          p := initStringi(100)
          b.ResetTimer()
          for i := 0; i < b.N; i++ {
              stringFmt(p)
          }
      }
      
      func BenchmarkStringJoin100(b *testing.B) {
          p := initStrings(100)
          b.ResetTimer()
          for i := 0; i < b.N; i++ {
              stringJoin(p)
          }
      }
      
      func BenchmarkStringBuffer100(b *testing.B) {
          p := initStrings(100)
          b.ResetTimer()
          for i := 0; i < b.N; i++ {
              stringBuffer(p)
          }
      }
      
      func BenchmarkStringBuilder100(b *testing.B) {
          p := initStrings(100)
          b.ResetTimer()
          for i := 0; i < b.N; i++ {
              stringBuilder(p)
          }
      }
      

    运行测试:

    go test -bench=. -benchtime=3s .
      goos: linux
      goarch: amd64
      pkg: ch18/main
      BenchmarkStringPlus100          119738         30039 ns/op
      BenchmarkStringFmt100          1000000          3178 ns/op
      BenchmarkStringJoin100         2409663          1513 ns/op
      BenchmarkStringBuffer100       1487332          2456 ns/op
      BenchmarkStringBuilder100      1730882          2070 ns/op
      PASS
      ok    ch18/main   24.062s
    

    从上面基准测试可以得出:

    1. 表现好的还是Join和Builder。
    2. 这两个方法的使用侧重点有些不一样, 如果有现成的数组、切片那么可以直接使用Join,但是如果没有,并且追求灵活性拼接,还是选择Builder。 Join还是定位于有现成切片、数组的(毕竟拼接成数组也要时间),并且使用固定方式进行分解的,比如逗号、空格等,局限比较大。

    相关文章

      网友评论

          本文标题:go 基准测试

          本文链接:https://www.haomeiwen.com/subject/kkeycrtx.html