美文网首页
Golang高效地拷贝big.Int

Golang高效地拷贝big.Int

作者: 幸运排骨虾 | 来源:发表于2018-09-18 16:23 被阅读0次

    错误的方式

    试图通过拷贝*big.Int指针所指的结构:

    a := big.NewInt(10)
    b := new(big.Int)
    *b = *a
    

    这种方式是错误的,因为big.Int结构内部有slice,拷贝结构的话内部的slice仍然是共享内存。

    点击运行测试

    正确的方式

    1.拷贝Bytes

    思想:

    序列化成[]bytes,然后拷贝

    func BenchmarkBigIntCopyBytes(b *testing.B) {
        b.ReportAllocs()
    
        old, _ := new(big.Int).SetString("100000000222222222222222222220000000000000000000", 10)
        new := new(big.Int)
        for i := 0; i < b.N; i++ {
            new.SetBytes(old.Bytes())
        }
    }
    

    2.反射赋值

    思想:

    通过反射赋值

    func BenchmarkBigIntCopier(b *testing.B) {
        b.ReportAllocs()
    
        old, _ := new(big.Int).SetString("100000000222222222222222222220000000000000000000", 10)
        new := new(big.Int)
        for i := 0; i < b.N; i++ {
            // "github.com/jinzhu/copier"
            copier.Copy(new, old)
        }
    
    }
    

    copier内部实现使用了reflect

    3. +0

    思想

    new = old = old + 0

    func TestCopyByAdd(t *testing.T) {
        old, _ := new(big.Int).SetString("100000000222222222222222222220000000000000000000", 10)
    
        new := new(big.Int)
        // new = old = old + 0
        new.Add(old, new)
        if old.Cmp(new) != 0 {
            t.FailNow()
        }
    
        new.Add(new, big.NewInt(1))
        t.Logf("old:%v,new:%v", old, new)
        if old.Cmp(new) >= 0 {
            t.FailNow()
        }
    }
    

    Benchmark测试

    func BenchmarkBigIntCopyByAdd(b *testing.B) {
        b.ReportAllocs()
    
        old, _ := new(big.Int).SetString("100000000222222222222222222220000000000000000000", 10)
        new := new(big.Int)
        for i := 0; i < b.N; i++ {
            // new = old = old + 0
            new.Add(old, new)
        }
    }
    

    性能对比

    big.Int = 10

    BenchmarkBigIntCopier-8     30000000            62.5 ns/op         0 B/op          0 allocs/op
    BenchmarkBigIntCopyBytes-8      30000000            46.7 ns/op         8 B/op          1 allocs/op
    BenchmarkBigIntCopyByAdd-8      100000000           20.8 ns/op         0 B/op          0 allocs/op
    

    big.Int = 100000000222222222222222222220000000000000000000

    BenchmarkBigIntCopier-8     30000000            60.8 ns/op         0 B/op          0 allocs/op
    BenchmarkBigIntCopyBytes-8      20000000            69.1 ns/op        32 B/op          1 allocs/op
    BenchmarkBigIntCopyByAdd-8      100000000           22.1 ns/op         0 B/op          0 allocs/op
    

    比较两次运行的结果,发现:

    • BenchmarkBigIntCopyBytes有额外的内存分配,其它两个方法则没有
    • big.Int值变大时,BenchmarkBigIntCopyBytes分配的内存增加,性能变差,结果BenchmarkBigIntCopier接近,甚至还差一点
    • BenchmarkBigIntCopyByAdd是性能最好的,没有额外的内存分配,且耗时稳定

    结论

    + 0 是最好的选择

    相关文章

      网友评论

          本文标题:Golang高效地拷贝big.Int

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