dongzuo4666 2017-03-28 22:09
浏览 25

64位无符号整数concat基准测试

I have a tweak question. I had some repetitive pieces of code in my web-app requests where simple things like fmt.Sprintf("%d%d", 01293123, 234993923) happens.

Now I did some benchmarks and tested a bytes writer, which was quite slow (~400 ns/op). The sprintf itself was about 240 ns/op. Then I did strings joining:

var concatBuffStr []byte

func BenchmarkStringsJoin(b *testing.B) {
    for n := 0; n < b.N; n++ {
        concatBuffStr = []byte(strings.Join([]string{
            strconv.Itoa(2),
            strconv.Itoa(3),
        }, " "))
    }
}

152 ns/op

A big improvement already. But then I tried clunking 2 ints converted to bytes together

var concatBuffStr []byte

func BenchmarkConcatIntsAsBytes(b *testing.B) {
    for n := 0; n < b.N; n++ {
        aBuf := make([]byte, 8)
        bBuf := make([]byte, 8)
        binary.BigEndian.PutUint64(aBuf, uint64(2))
        binary.BigEndian.PutUint64(bBuf, uint64(3))
        concatBuffStr = append(aBuf, bBuf...)
    }
}

57.8 ns/op

Amazing! But I could just avoid glueing them together and already reserve the full 16 bytes for 2 maxed out 64 bit uints spaces:

var concatBuffStr []byte

func BenchmarkCopyIntsAsBytes(b *testing.B) {
    for n := 0; n < b.N; n++ {
        concatBuffStr = make([]byte, 16)
        bBuf := make([]byte, 8)
        binary.BigEndian.PutUint64(concatBuffStr, uint64(123123))
        binary.BigEndian.PutUint64(bBuf, uint64(3453455))
        copy(concatBuffStr[8:], bBuf)
    }
}

30.4 ns/op

By now we're 8 times faster than with the fmt.Sprintf() method.

Was wondering if there is an even faster way than this. I want to avoid unsafe tho.

I was also thinking of checking the max value of both 2 ints and if they are below the MAX of an uint32 or uint16 I could customize the logic. Benchmarking the uint16 downgrade by hand is around 23 ns/op, but that's not realistic as in the web-request itself it would still need to check the size of the ints and do extra logic, which will likely result in more overhead than that 7 ns/op gain.

Update

I managed to simplify it a little bit more:

var concatBuffStr []byte

func BenchmarkCopyIntsAsBytesShort(b *testing.B) {
    for n := 0; n < b.N; n++ {
        concatBuffStr = make([]byte, 16)
        binary.BigEndian.PutUint64(concatBuffStr, uint64(123123))
        binary.BigEndian.PutUint64(concatBuffStr[8:], uint64(3453455))
    }
}

28.6 ns/op
  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 ETLCloud 处理json多层级问题
    • ¥15 matlab中使用gurobi时报错
    • ¥15 这个主板怎么能扩出一两个sata口
    • ¥15 不是,这到底错哪儿了😭
    • ¥15 2020长安杯与连接网探
    • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么
    • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
    • ¥15 可见光定位matlab仿真
    • ¥15 arduino 四自由度机械臂
    • ¥15 wordpress 产品图片 GIF 没法显示