「2」浅试 Golang tesing|青训营笔记

139 阅读2分钟

「2」Golang 工程化

这是我参与「第三届青训营 -后端场」笔记创作活动的的第二篇笔记。

创建时间: May 16, 2022 4:43 PM

「5.7」青训营 Golang 工程化课程,笔记整理。

测试 - 工程化

💡 早些时候用过 testing.T 在算法课设上,用它来简单做一些测试。所以课后只实践了 testing.Benchmark 和 Mock 部分。

GoBenchmark

  • 定义

    type Server intvar (
        Servers [10]Server
    )
    ​
    func init() {
        InitServers()
    }
    ​
    func InitServers() {
        for i, _ := range Servers {
            Servers[i] = Server(i + maxIdx)
        }
    }
    ​
    func Select() Server {
        return Servers[rand.Intn(len(Servers))]
    }
    ​
    func FastSelect() Server {
        return Servers[fastrand.Intn(len(Servers))]
    }
    
  • 测试

    // init 取代 b.ResetTimer()
    ​
    func BenchmarkSelect(b *testing.B) {
        for i := 0; i < b.N; i++ {
            Select()
        }
    }
    ​
    func BenchmarkSelectParallel(b *testing.B) {
        b.RunParallel(func(pb *testing.PB) {
            for pb.Next() {
                Select()
            }
        })
    }
    ​
    func BenchmarkFastSelect(b *testing.B) {
        for i := 0; i < b.N; i++ {
            FastSelect()
        }
    }
    ​
    func BenchmarkFastSelectParallel(b *testing.B) {
        b.RunParallel(func(pb *testing.PB) {
            for pb.Next() {
                FastSelect()
            }
        })
    }
    

  这里的记录中的代码和老师课上的稍有调整,我用 func init() 代替了 b.ResetTimer() 在我的理解中这样的修改应该是等价于重置时间的。

  • 本机运行结果

BenchmarkXX-8 对应 GOMAXPROCS 核心数

cpu: Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz
BenchmarkSelect
BenchmarkSelect-8                       63568075                20.85 ns/op
BenchmarkSelectParallel
BenchmarkSelectParallel-8                9219620               124.1 ns/op
BenchmarkFastSelect
BenchmarkFastSelect-8                   165717588                6.649 ns/op
BenchmarkFastSelectParallel
BenchmarkFastSelectParallel-8           673691774                2.093 ns/op

对比结果,发现fastrand 性能应该优于 rand 的,并且并发场景下两者差距非常明显接近 60x。

课后注意到 PPT 中的留言提到 rand.Intn() 出现并发情况下性能骤降的原因是 rand 实现中维护了一把锁

简单找了一下源码

type lockedSource struct {
   lk  sync.Mutex
   src *rngSource
}
// line: 387
func (r *lockedSource) Int63() (n int64) {
    r.lk.Lock()
    n = r.src.Int63()
    r.lk.Unlock()
    return
}

发现 rand 每次请求随机数都会操作这把资源锁,在并发场景下确实会带来性能瓶颈。

Mock 测试

Mock 曾经完全没接触过,用下来感觉是非常 Hack 的玩法。

monkey.Patch 可以插桩修改一个函数调用的返回结果。

Lab time

  1. 支持发布帖子

  2. 本地 ID 生成需要保证不重复、唯一性

    1. 雪花算法

      1. 前xxx位记录时间戳,后几位分配为id
      2. 序列号对应的时间戳会被保存,每次读取时间戳,如果时间戳相同,对序列号原子操作加一,组合成 uuid。
  3. Append 文件,更新索引,注意 Map 的并发安全问题

    1. 分片加锁 map