Go按位运算性能之谜

在对从字节数组到 s 的转换性能进行基准测试时uint32,我注意到从最低有效位开始时转换运行得更快:


package blah


import (

    "testing"

    "encoding/binary"

    "bytes"

)


func BenchmarkByteConversion(t *testing.B) {

    var i uint32 = 3419234848

    buf := new(bytes.Buffer)

    _ = binary.Write(buf, binary.BigEndian, i)

    b := buf.Bytes()


    for n := 0; n < t.N; n++ {

        // Start with least significant bit: 0.27 nanos

        value := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[2])<<16 | uint32(b[0])<<24


        // Start with most significant bit: 0.68 nanos

        // value := uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])

        _ = value

    }

}

当我运行时,计算第一种方式go test -bench=.时每次迭代获得 0.27 纳米,计算第二种方式时每次迭代获得 0.68 纳米。为什么将数字放在一起时从最低有效位开始的速度是原来的两倍?valuevalue|


慕码人2483693
浏览 72回答 1
1回答

幕布斯6054654

没有什么神秘之处。优化!package blahimport (&nbsp; &nbsp; "bytes"&nbsp; &nbsp; "encoding/binary"&nbsp; &nbsp; "testing")func BenchmarkByteConversionLeast(t *testing.B) {&nbsp; &nbsp; var i uint32 = 3419234848&nbsp; &nbsp; buf := new(bytes.Buffer)&nbsp; &nbsp; _ = binary.Write(buf, binary.BigEndian, i)&nbsp; &nbsp; b := buf.Bytes()&nbsp; &nbsp; for n := 0; n < t.N; n++ {&nbsp; &nbsp; &nbsp; &nbsp; // Start with least significant bit: 0.27 nanos&nbsp; &nbsp; &nbsp; &nbsp; value := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[2])<<16 | uint32(b[0])<<24&nbsp; &nbsp; &nbsp; &nbsp; _ = value&nbsp; &nbsp; }}func BenchmarkByteConversionMost(t *testing.B) {&nbsp; &nbsp; var i uint32 = 3419234848&nbsp; &nbsp; buf := new(bytes.Buffer)&nbsp; &nbsp; _ = binary.Write(buf, binary.BigEndian, i)&nbsp; &nbsp; b := buf.Bytes()&nbsp; &nbsp; for n := 0; n < t.N; n++ {&nbsp; &nbsp; &nbsp; &nbsp; // Start with most significant bit: 0.68 nanos&nbsp; &nbsp; &nbsp; &nbsp; value := uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])&nbsp; &nbsp; &nbsp; &nbsp; _ = value&nbsp; &nbsp; }}输出:go test silly_test.go -bench=.goos: linuxgoarch: amd64BenchmarkByteConversionLeast-4&nbsp; &nbsp; &nbsp; 2000000000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0.72 ns/opBenchmarkByteConversionMost-4&nbsp; &nbsp; &nbsp; &nbsp;2000000000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1.80 ns/op这应该是显而易见的。边界检查消除。只需使用常识。如果检查索引 3、2、1 和 0 的数组边界,则可以在 3 处停止检查,因为显然 2、1 和 0 也是有效的。如果检查索引 0、1、2 和 3 的数组边界,则必须检查所有索引的边界。一次边界检查与四次边界检查。维基百科:边界检查维基百科:边界检查消除您还应该阅读好的代码,例如 Go 标准库。例如,func (littleEndian) PutUint64(b []byte, v uint64) {&nbsp; &nbsp; _ = b[7] // early bounds check to guarantee safety of writes below&nbsp; &nbsp; b[0] = byte(v)&nbsp; &nbsp; b[1] = byte(v >> 8)&nbsp; &nbsp; b[2] = byte(v >> 16)&nbsp; &nbsp; b[3] = byte(v >> 24)&nbsp; &nbsp; b[4] = byte(v >> 32)&nbsp; &nbsp; b[5] = byte(v >> 40)&nbsp; &nbsp; b[6] = byte(v >> 48)&nbsp; &nbsp; b[7] = byte(v >> 56)}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go