go语言扩展包,收集一些常用的操作函数,辅助更快的完成开发工作,并减少重复代码

go-extend

GoDoc Actions Status codecov Go Report Card GitHub release

go-extend 收集一些常用的操作函数,辅助更快的完成开发工作,并减少重复代码。

它收集各种杂项函数,并进行归类,方便使用者查找,它可以大幅度提升开发效率和程序运行性能。它以保证性能为最大前提,提供有效的方法。 针对一些标准库中的函数或者库进行一些修改,使其性能大幅度提升,但它并不用来替换标准库函数,这些函数往往会在一些场景下有效,但有些函数可以用来替换标准库函数,它们保持一致的功能,且相当安全。

一些包或者函数使用示例及分析可以在我的 博客(https://blog.thinkeridea.com) 中找到。

安装

$ go get  github.com/thinkeridea/go-extend/...

规范:

  • 与标准库包名一致的使用 ex 前缀, 避免与标准库包冲突
  • 包目录下 doc.go 作为包说明文档

性能测试

包中一些函数会进行性能测试,包括每次修订的性能对比,它们一般位于各自包下面的 benchmark 目录下,性能测试结果可以在 benchmark.md 快速浏览。

标准库函数改进列表

用来替换标准库的函数,它们和标准库函数功能保持一致,并拥有更好的性能:

  • exstrings.Join 该方法是对标准库 strings.Join 修改,配合 unsafe 包能有效减少内存分配
  • exstrings.Repeat 该方法是对标准库 strings.Repeat 修改,对于创建大字符串能有效减少内存分配
  • exstrings.Replace 替换字符串 该方法是对标准库 strings.Replace 修改,配合 unsafe 包能有效减少内存分配

用该改善标准库的函数,它们基本和标准库功能一致,但是它们都拥有更好的性能:

许可

go-extend 根据 MIT License 许可证授权,有关完整许可证文本,请参阅 LICENSE

Comments
  • exstrings.Reverse 性能改进

    exstrings.Reverse 性能改进

    该方法收集于官网 How to write Go code 中的一个代码片段,因曾经面试遇到这个面试题而留心。

    近期回答 Go Forum 中关于 [SOLVED] String size of 20 character 中字符串长度截取使用 []rune 类型与字符串类型转换,期望处理安全的 unicode 字符。

    我对此方法提出了性能质疑,编写了基于 utf8.DecodeRuneInString 的计算版本,并做了性能测试 相关回复在这里 发现两个种方法性能差距惊人。

    我想到了 go-extend 中的 exstrings.Reverse 方法也是用了类似的类型转换,所以我做了一个小的实验来测试不同实现的性能。

  • Update: UnsafeToBytes

    Update: UnsafeToBytes

    More faster

    $ go test -count=50 -bench=BenchmarkUnsafeToBytes > old.txt
    $ go test -count=50 -bench=BenchmarkUnsafeToBytes > new.txt
    
    $ benchcmp old.txt new.txt           
    benchmark                    old ns/op     new ns/op     delta
    BenchmarkUnsafeToBytes-4     0.50          0.38          -22.78%
    BenchmarkUnsafeToBytes-4     0.36          0.35          -2.77%
    BenchmarkUnsafeToBytes-4     0.55          0.35          -35.75%
    BenchmarkUnsafeToBytes-4     0.37          0.36          -4.03%
    BenchmarkUnsafeToBytes-4     0.33          0.35          +4.50%
    BenchmarkUnsafeToBytes-4     0.36          0.35          -2.79%
    BenchmarkUnsafeToBytes-4     0.33          0.33          +0.60%
    BenchmarkUnsafeToBytes-4     0.35          0.33          -5.17%
    BenchmarkUnsafeToBytes-4     0.35          0.34          -4.51%
    BenchmarkUnsafeToBytes-4     0.36          0.33          -8.94%
    BenchmarkUnsafeToBytes-4     0.38          0.33          -13.09%
    BenchmarkUnsafeToBytes-4     0.36          0.34          -5.28%
    BenchmarkUnsafeToBytes-4     0.37          0.35          -5.08%
    BenchmarkUnsafeToBytes-4     0.37          0.43          +14.75%
    BenchmarkUnsafeToBytes-4     0.35          0.35          +0.29%
    BenchmarkUnsafeToBytes-4     0.35          0.37          +7.23%
    BenchmarkUnsafeToBytes-4     0.39          0.36          -7.24%
    BenchmarkUnsafeToBytes-4     0.36          0.36          -0.28%
    BenchmarkUnsafeToBytes-4     0.35          0.35          +0.57%
    BenchmarkUnsafeToBytes-4     0.35          0.34          -3.97%
    BenchmarkUnsafeToBytes-4     0.34          0.34          -0.29%
    BenchmarkUnsafeToBytes-4     0.33          0.35          +6.01%
    BenchmarkUnsafeToBytes-4     0.39          0.34          -14.10%
    BenchmarkUnsafeToBytes-4     0.55          0.34          -38.84%
    BenchmarkUnsafeToBytes-4     0.41          0.34          -17.23%
    BenchmarkUnsafeToBytes-4     0.38          0.36          -2.67%
    BenchmarkUnsafeToBytes-4     0.37          0.38          +2.71%
    BenchmarkUnsafeToBytes-4     0.37          0.34          -7.65%
    BenchmarkUnsafeToBytes-4     0.42          0.34          -18.25%
    BenchmarkUnsafeToBytes-4     0.37          0.37          -1.88%
    BenchmarkUnsafeToBytes-4     0.37          0.36          -2.73%
    BenchmarkUnsafeToBytes-4     0.41          0.35          -14.56%
    BenchmarkUnsafeToBytes-4     0.35          0.35          +2.31%
    BenchmarkUnsafeToBytes-4     0.35          0.36          +1.98%
    BenchmarkUnsafeToBytes-4     0.37          0.36          -2.72%
    BenchmarkUnsafeToBytes-4     0.39          0.34          -11.11%
    BenchmarkUnsafeToBytes-4     0.47          0.35          -26.27%
    BenchmarkUnsafeToBytes-4     0.39          0.34          -11.40%
    BenchmarkUnsafeToBytes-4     0.43          0.36          -16.47%
    BenchmarkUnsafeToBytes-4     0.36          0.34          -5.22%
    BenchmarkUnsafeToBytes-4     0.36          0.37          +0.82%
    BenchmarkUnsafeToBytes-4     0.39          0.34          -12.73%
    BenchmarkUnsafeToBytes-4     0.40          0.36          -9.00%
    BenchmarkUnsafeToBytes-4     0.39          0.34          -13.55%
    BenchmarkUnsafeToBytes-4     0.36          0.40          +11.36%
    BenchmarkUnsafeToBytes-4     0.60          0.36          -40.73%
    BenchmarkUnsafeToBytes-4     0.36          0.34          -6.58%
    BenchmarkUnsafeToBytes-4     0.38          0.33          -12.37%
    BenchmarkUnsafeToBytes-4     0.39          0.33          -13.47%
    BenchmarkUnsafeToBytes-4     0.39          0.34          -13.40%
    
  • 动态评估bytes.Buffer的需求的容量,全局共享bytes.Buffer池

    动态评估bytes.Buffer的需求的容量,全局共享bytes.Buffer池

    采用全局共享不同容量区间(采用2的幂次方来划分),一共 22 个区间,最小64 byte, 最大 256 MB, 根据动态计算,在获取 bytes.Buffer 时从相应桶的 sync.Pool 来获取,以减少多余的内存浪费及bytes.Buffer 扩容次数。

    相较于使用固定容量的 sync.Pool 在需求容量动态波动时可以获取30~40倍的性能提升(这并不包含GC带来的性能提升,那将是更令人兴奋的),在内存分配上可以减少近300倍。

    即使在每次都获取固定容量,且不发生扩容的情况(这会导致动态池只是用单个桶), sync.Pool并没有带来很大的惊喜,动态池相较于 sync.Pool 性能略下降 28%, 单次约 17ns, 即使这样这依然让人振奋,大多数我们都在处理不同大小的数据,使用动态bytes.Buffer共享池我们将收益巨大。

    goos: darwin
    goarch: amd64
    pkg: github.com/thinkeridea/go-extend/pool/benchmark
    BenchmarkBufferPool
    BenchmarkBufferPool-8                    1088794              1102 ns/op             387 B/op          0 allocs/op
    BenchmarkBufferSyncPool
    BenchmarkBufferSyncPool-8                  49735             37895 ns/op          115277 B/op          0 allocs/op
    BenchmarkBufferFixedSizePool
    BenchmarkBufferFixedSizePool-8          27296764                42.7 ns/op             0 B/op          0 allocs/op
    BenchmarkBufferFixedSizeSyncPool
    BenchmarkBufferFixedSizeSyncPool-8      26099842                59.6 ns/op           192 B/op          0 allocs/op
    PASS
    ok      github.com/thinkeridea/go-extend/pool/benchmark 8.627s
    
  • exmath.Round 精度为负数时结果精准度问题 #14

    exmath.Round 精度为负数时结果精准度问题 #14

    该提交用于修复 #14 精度问题,其原因为 precision < 0 其参与计算的浮点数比较小,导致最终运算结果精度得不到保证

    分别处理 precision = 0precision <0precision > 0 的情况,以保证精准度为核心目标。

    新实现相较于旧方案性能略有下降:

    name            old time/op  new time/op  delta
    Round-8         3.45ns ± 1%  4.04ns ±14%  +17.25%  (p=0.000 n=44+46)
    RoundDecimal-8  3.47ns ± 1%  3.86ns ± 2%  +11.17%  (p=0.000 n=40+50)
    RoundInteger-8  4.38ns ± 1%  5.14ns ± 1%  +17.38%  (p=0.000 n=49+48)
    
  • 调优exmath.Round算法

    调优exmath.Round算法

    调优 exmath.Round 算法,获得接近 16% 的性能提升

    $ benchstat old.txt new.txt

    name old time/op new time/op delta Round-8 4.20ns ± 3% 3.50ns ± 4% -16.69% (p=0.000 n=44+49)

    $ benchcmp old.txt new.txt

    benchcmp is deprecated in favor of benchstat: https://pkg.go.dev/golang.org/x/perf/cmd/benchstat benchmark old ns/op new ns/op delta BenchmarkRound-8 5.50 3.55 -35.45% BenchmarkRound-8 4.50 3.49 -22.44% BenchmarkRound-8 4.45 3.47 -22.02% BenchmarkRound-8 4.35 3.57 -17.93% BenchmarkRound-8 4.56 3.45 -24.34% BenchmarkRound-8 4.84 3.47 -28.31% BenchmarkRound-8 4.19 3.46 -17.42% BenchmarkRound-8 4.16 3.47 -16.59% BenchmarkRound-8 4.16 3.48 -16.35% BenchmarkRound-8 4.17 3.48 -16.55% BenchmarkRound-8 4.16 3.46 -16.83% BenchmarkRound-8 4.18 3.48 -16.75% BenchmarkRound-8 4.19 3.48 -16.95% BenchmarkRound-8 4.23 3.47 -17.97% BenchmarkRound-8 4.18 3.56 -14.83% BenchmarkRound-8 4.23 3.71 -12.29% BenchmarkRound-8 4.14 3.60 -13.04% BenchmarkRound-8 4.18 3.62 -13.40% BenchmarkRound-8 4.19 3.58 -14.56% BenchmarkRound-8 4.30 3.59 -16.51% BenchmarkRound-8 4.27 3.53 -17.33% BenchmarkRound-8 4.25 3.47 -18.35% BenchmarkRound-8 4.29 3.46 -19.35% BenchmarkRound-8 4.24 3.47 -18.16% BenchmarkRound-8 4.23 3.57 -15.60% BenchmarkRound-8 4.16 3.47 -16.59% BenchmarkRound-8 4.23 3.56 -15.84% BenchmarkRound-8 4.24 3.58 -15.57% BenchmarkRound-8 4.19 3.48 -16.95% BenchmarkRound-8 4.22 3.46 -18.01% BenchmarkRound-8 4.19 3.48 -16.95% BenchmarkRound-8 4.23 3.46 -18.20% BenchmarkRound-8 4.17 3.47 -16.79% BenchmarkRound-8 4.25 3.63 -14.59% BenchmarkRound-8 4.17 3.47 -16.79% BenchmarkRound-8 4.14 3.46 -16.43% BenchmarkRound-8 4.21 3.46 -17.81% BenchmarkRound-8 4.15 3.47 -16.39% BenchmarkRound-8 4.23 3.44 -18.68% BenchmarkRound-8 4.18 3.48 -16.75% BenchmarkRound-8 4.17 3.46 -17.03% BenchmarkRound-8 4.20 3.47 -17.38% BenchmarkRound-8 4.33 3.47 -19.86% BenchmarkRound-8 4.19 3.47 -17.18% BenchmarkRound-8 4.17 3.48 -16.55% BenchmarkRound-8 4.18 3.52 -15.79% BenchmarkRound-8 4.17 3.49 -16.31% BenchmarkRound-8 4.19 3.47 -17.18% BenchmarkRound-8 4.17 3.47 -16.79% BenchmarkRound-8 4.16 3.57 -14.18%

  • 加快内网地址检查,172.16~31.0.0/12 其掩码地址均为 172.16.0.0/12 存在重复

    加快内网地址检查,172.16~31.0.0/12 其掩码地址均为 172.16.0.0/12 存在重复

    "10.0.0.0/8",
    "169.254.0.0/16",
    "172.16.0.0/12",
    "172.17.0.0/12",
    "172.18.0.0/12",
    "172.19.0.0/12",
    "172.20.0.0/12",
    "172.21.0.0/12",
    "172.22.0.0/12",
    "172.23.0.0/12",
    "172.24.0.0/12",
    "172.25.0.0/12",
    "172.26.0.0/12",
    "172.27.0.0/12",
    "172.28.0.0/12",
    "172.29.0.0/12",
    "172.30.0.0/12",
    "172.31.0.0/12",
    "192.168.0.0/16",	
    

    172.16~31.0.0/12 其掩码地址均为 172.16.0.0/12 存在重复。

    使用直接对比ip段前两段数据检查,不使用 network.Contains 判断,在暂时不支持IPV6 的前提下,这种方法更加高效。

  • 改变 pool.NewBuffer 的行为,响应固定容量的BufferPool

    改变 pool.NewBuffer 的行为,响应固定容量的BufferPool

    pool.NewBuffer 在 #16 中引入的方法,实现根据实际使用场景动态评估默认 bytes.Buffer 容量的方法,因测试存在bug(在 #17 #18 中发现及修复) 后被弃用,但是考虑 BufferPool 接口可以简化使用 sync.Pool 获取及响应 bytes.Buffer实例,故通过改变 pool.NewBuffer 的行为,响应一个独立的非共享的 BufferPool,每次调用都会返回新的 BufferPool

  • “动态评估bytes.Buffer的需求的容量,全局共享bytes.Buffer池” 这个pr存在性能测试问题,导致结果存在偏差

    “动态评估bytes.Buffer的需求的容量,全局共享bytes.Buffer池” 这个pr存在性能测试问题,导致结果存在偏差

    #16 在性能测试时,对SyncPool 测试时并没有对 Buffer 进行 Reset 操作,导致大量内存分配,测试结果没有参考性。

    在完善测试用例后,以下测试结果并没有相较 sync.Pool 有明显优势,且可能对性能产生影响。

    goos: darwin
    goarch: amd64
    pkg: github.com/thinkeridea/go-extend/pool/benchmark
    BenchmarkBufferPool
    BenchmarkBufferPool-8                     943312              1065 ns/op               1 B/op          0 allocs/op
    BenchmarkBufferSyncPool
    BenchmarkBufferSyncPool-8                1000000              1032 ns/op               0 B/op          0 allocs/op
    BenchmarkBufferFixedSizePool
    BenchmarkBufferFixedSizePool-8          29174670                44.1 ns/op             0 B/op          0 allocs/op
    BenchmarkBufferFixedSizeSyncPool
    BenchmarkBufferFixedSizeSyncPool-8      38488425                28.1 ns/op             0 B/op          0 allocs/op
    PASS
    ok      github.com/thinkeridea/go-extend/pool/benchmark 5.236s
    
  • 扩展exstrings函数

    扩展exstrings函数

    • 优化 exstrings.Reverse 方法,使其代码更加易读,并进行多种反转字符串方法性能对比,其测试代码在exstrings/benchmark/reverse_test.go, 其中BenchmarkReverseUTF8DecodeRuneInString 是优化前版本, BenchmarkExstringsReverse 是优化有版本,性能提升约3%,其结果如下:
    $ go test -benchmem -bench="Reverse"  
    goos: darwin
    goarch: amd64
    pkg: github.com/thinkeridea/go-extend/exstrings/benchmark
    BenchmarkReverseRunes-8                           703830              1700 ns/op             480 B/op          2 allocs/op
    BenchmarkReverseRange-8                          1400299               861 ns/op             192 B/op          1 allocs/op
    BenchmarkReverseUTF8DecodeRuneInString-8         1482175               717 ns/op             192 B/op          1 allocs/op
    BenchmarkExstringsReverse-8                      1698225               694 ns/op             192 B/op          1 allocs/op
    PASS
    ok      github.com/thinkeridea/go-extend/exstrings/benchmark    7.995s
    
    • 创建一个 exstrings.Bytes 方法,用来替换 []byte(s),相比 []byte(s) 转换类型提升 14%,这仅仅是一个趣味函数,性能测试代码exstrings/benchmark/convert_test.go 结果如下:
    $ go test -benchmem -bench="StringToBytes"  
    goos: darwin
    goarch: amd64
    pkg: github.com/thinkeridea/go-extend/exstrings/benchmark
    BenchmarkStandardLibraryStringToBytes-8         19118637                64.0 ns/op           192 B/op          1 allocs/op
    BenchmarkExstringsStringToBytes-8               22079703                55.1 ns/op           192 B/op          1 allocs/op
    PASS
    ok      github.com/thinkeridea/go-extend/exstrings/benchmark    4.426s
    
    • 添加 exutf8.RuneSub 别名 exbytes.Sub
    • 添加 exutf8.RuneSubString 别名 exstrings.SubString