将字符串转换为二进制的字符串表示的有效方法

时间:2017-10-20 12:15:41

标签: string performance go binary type-conversion

我正在搜索如何将字符串转换为具有最佳性能的二进制字符串表示形式。

所以我从以下类似的东西开始:

func binConvertOrig(s string) string {
    var buf bytes.Buffer
    for i := 0; i < len(s); i++ {
        fmt.Fprintf(&buf, "%08b", s[i])
    }
    return buf.String()
}

s := "Test"
log.Printf("%s => binConvertOrig => %s", s, binConvertOrig(s))

但似乎是fmt.Fprintf&amp; bytes.Buffer效率不高。

有更好的方法吗?

由于

1 个答案:

答案 0 :(得分:3)

没有什么比预先计算的查找表更好,特别是如果它存储在切片或数组中(而不是映射中),并且转换器为结果分配一个字节切片,其大小合适: / p>

var byteBinaries [256][]byte

func init() {
    for i := range byteBinaries {
        byteBinaries[i] = []byte(fmt.Sprintf("%08b", i))
    }
}

func strToBin(s string) string {
    res := make([]byte, len(s)*8)
    for i := len(s) - 1; i >= 0; i-- {
        copy(res[i*8:], byteBinaries[s[i]])
    }
    return string(res)
}

测试它:

fmt.Println(strToBin("\x01\xff"))

输出(在Go Playground上尝试):

0000000111111111

基准

让我们看看它有多快:

var texts = []string{
    "\x00",
    "123",
    "1234567890",
    "asdf;lkjasdf;lkjasdf;lkj108fhq098wf34",
}

func BenchmarkOrig(b *testing.B) {
    for n := 0; n < b.N; n++ {
        for _, t := range texts {
            binConvertOrig(t)
        }
    }
}

func BenchmarkLookup(b *testing.B) {
    for n := 0; n < b.N; n++ {
        for _, t := range texts {
            strToBin(t)
        }
    }
}

结果:

BenchmarkOrig-4      200000     8526 ns/op       2040 B/op     12 allocs/op
BenchmarkLookup-4   2000000      781 ns/op        880 B/op      8 allocs/op

查找版本(strToBin()快11倍并且使用更少的内存和分配。基本上它只使用分配结果(这是不可避免的)。