在Golang中生成固定长度的随机十六进制字符串的有效方法? [英] Efficient way to to generate a random Hex string of a fixed length in Golang?

查看:106
本文介绍了在Golang中生成固定长度的随机十六进制字符串的有效方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要生成许多固定长度的随机十六进制字符串. 我找到了这种解决方案如何在golang中生成固定长度的随机字符串?

I need to generate a lot of a random hex string of a fixed length. I find this solution How to generate a random string of a fixed length in golang?

我正在做这样的事情:

const letterBytes = "abcdef0123456789"
const (
    letterIdxBits = 6                    // 6 bits to represent a letter index
    letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
    letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

var src = rand.NewSource(time.Now().UnixNano())

// RandStringBytesMaskImprSrc ...
// Src: https://stackoverflow.com/a/31832326/710955
func RandStringBytesMaskImprSrc(n int) string {
    b := make([]byte, n)
    // A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
    for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
        if remain == 0 {
            cache, remain = src.Int63(), letterIdxMax
        }
        if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
            b[i] = letterBytes[idx]
            i--
        }
        cache >>= letterIdxBits
        remain--
    }

    return string(b)
}

var tryArr = make([]string, 10000)
for i := 0; i < 10000; i++ {
    tryArr[i] = RandStringBytesMaskImprSrc(8)
}

但是我遇到了这个紧急错误

But I got this panic error

panic: runtime error: index out of range

goroutine 36 [running]:
math/rand.(*rngSource).Int63(0x11bb1300, 0x8, 0x8)
    D:/Applications/Go/src/math/rand/rng.go:231 +0xa0
main.RandStringBytesMaskImprSrc(0x8, 0x11f81be8, 0x8)
    main.go:60 +0x5f

错误似乎在for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0;中,但我不知道为什么会出现此错误.

The errror seem to be in for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0;, but I don't find why there is this error.

在Go中生成大量固定长度的随机十六进制字符串的最快,最简单的方法是什么?

What is the fastest and simplest way to generate a lot of a random hex string of a fixed length in Go?

基准

package bench

import (
    "encoding/hex"
    "math/rand"
    "testing"
    "time"
)

const letterBytes = "abcdef0123456789"
const (
    letterIdxBits = 4                    // 4 bits to represent a letter index
    letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
    letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

var src1 = rand.NewSource(time.Now().UnixNano())
var src2 = rand.New(rand.NewSource(time.Now().UnixNano()))

// RandStringBytesMaskImprSrc returns a random hexadecimal string of length n.
func RandStringBytesMaskImprSrc1(n int) string {
    b := make([]byte, n)
    for i, cache, remain := n-1, src1.Int63(), letterIdxMax; i >= 0; {
        if remain == 0 {
            cache, remain = src1.Int63(), letterIdxMax
        }
        if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
            b[i] = letterBytes[idx]
            i--
        }
        cache >>= letterIdxBits
        remain--
    }

    return string(b)
}

func RandStringBytesMaskImprSrc2(n int) string {
    b := make([]byte, (n+1)/2) // can be simplified to n/2 if n is always even

    if _, err := src2.Read(b); err != nil {
        panic(err)
    }

    return hex.EncodeToString(b)[:n]
}

func BenchmarkRandStringBytesMaskImprSrc1(b *testing.B) {
    for n := 0; n < b.N; n++ {
        _ = RandStringBytesMaskImprSrc1(8)
    }
}

func BenchmarkRandStringBytesMaskImprSrc2(b *testing.B) {
    for n := 0; n < b.N; n++ {
        _ = RandStringBytesMaskImprSrc2(8)
    }
}


goos: windows
goarch: 386
BenchmarkRandStringBytesMaskImprSrc1-4          20000000               116 ns/op              16 B/op          2 allocs/op
BenchmarkRandStringBytesMaskImprSrc2-4          10000000               231 ns/op              24 B/op          3 allocs/op
PASS
ok      command-line-arguments  5.139s

=> icza RandStringBytesMaskImprSrc解决方案更有效

=> icza RandStringBytesMaskImprSrcsolution is more efficient

推荐答案

实际上,您发布的代码可以运行,即使其中有错误(请参见下文),它也不会引起恐慌(只会使性能变差) ).

Actually the code you posted runs, as even though there's a mistake in it (see below), it still doesn't cause a panic (just makes performance worse).

您发布的堆栈跟踪指示math/rand软件包中的错误,我没有遇到过.请发布完整代码和Go版本+ env(go versiongo env).

The stack trace you posted indicates error in the math/rand package, I did not experience it. Please post full code and Go version + env (go version and go env).

事实证明,询问者正在同时从多个goroutines调用RandStringBytesMaskImprSrc(). RandStringBytesMaskImprSrc()使用共享的rand.Source实例,该实例对于并发使用是不安全的,因此math/rand程序包会出现恐慌.解决方法是为每个goroutine创建一个单独的rand.Source(),并将其传递给RandStringBytesMaskImprSrc().

As it turns out, the asker was calling RandStringBytesMaskImprSrc() concurrently, from multiple goroutines. RandStringBytesMaskImprSrc() uses a shared rand.Source instance which is not safe for concurrent use, hence the panic from the math/rand package. Fix is to create a separate rand.Source() for each goroutines, and pass that to RandStringBytesMaskImprSrc().

在配置"中有一个错误.开头的常量:

There is a mistake in the "configuration" constants at the beginning:

const letterBytes = "abcdef0123456789"
const (
    letterIdxBits = 6                    // 6 bits to represent a letter index
    letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
    letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
)

常数letterIdxBits应包含表示符号索引所需的位数.由于您使用的字母是16个元素(长度为letterBytes),因此16个组合仅需要4位:

The constant letterIdxBits should contain how many bits are required to represent a symbol index. Since you're using an alphabet of 16 elements (the length of letterBytes), 16 combinations require only 4 bits:

letterIdxBits = 4                    // 4 bits to represent a letter index

测试示例:

var tryArr = make([]string, 10)
for i := range tryArr {
    tryArr[i] = RandStringBytesMaskImprSrc(8)
}
fmt.Println(tryArr)

输出(在游乐场上尝试):

[d3e7caa6 a69c9b7d c37a613b 92d5a43b 64059c4a 4f08141b 70130c65 1546daaf fe140fcd 0d714e4d]

(注意:由于Go游乐场的开始时间是固定的,并且输出已缓存,您将始终看到这些随机生成的字符串.在计算机上运行以查看随机结果.)

(Note: since the starting time on the Go playground is fixed and output is cached, you will always see these random generated strings. Run it on your machine to see random results.)

这篇关于在Golang中生成固定长度的随机十六进制字符串的有效方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆