在Go中生成长随机字符串的最快方法是什么?

Pav*_*lau 14 string random go

像[a-zA-Z0-9]字符串一样:

na1dopW129T0anN28udaZ

或十六进制字符串:

8c6f78ac23b4a7b8c0182d

我的意思是2K以上的字符.

Bil*_*ard 22

您可以使用Go package uniuri生成随机字符串(或查看源代码以了解它们是如何进行的).你会想要使用:

func NewLen(length int) string
Run Code Online (Sandbox Code Playgroud)

NewLen返回提供长度的新随机字符串,由标准字符组成.

或者,指定使用的字符集:

func NewLenChars(length int, chars []byte) string
Run Code Online (Sandbox Code Playgroud)


Dus*_*tin 22

这在我的盒子上大约200MBps.有明显的改进空间.

type randomDataMaker struct {
    src rand.Source
}

func (r *randomDataMaker) Read(p []byte) (n int, err error) {
    for i := range p {
        p[i] = byte(r.src.Int63() & 0xff)
    }
    return len(p), nil
}
Run Code Online (Sandbox Code Playgroud)

你只是io.CopyN用来制作你想要的字符串.显然你可以在路上或其他任何地方调整字符集.

关于这个模型的好处是,它只是一个io.Reader你可以使用它制作任何东西.

测试如下:

func BenchmarkRandomDataMaker(b *testing.B) {
    randomSrc := randomDataMaker{rand.NewSource(1028890720402726901)}
    for i := 0; i < b.N; i++ {
        b.SetBytes(int64(i))
        _, err := io.CopyN(ioutil.Discard, &randomSrc, int64(i))
        if err != nil {
            b.Fatalf("Error copying at %v: %v", i, err)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的2.2GHz i7的一个核心:

BenchmarkRandomDataMaker       50000        246512 ns/op     202.83 MB/s
Run Code Online (Sandbox Code Playgroud)

编辑

自从我编写基准测试以来,我认为我会做一些明显的改进(不经常调用随机).有了1/8的rand调用,它的运行速度提高了大约4倍,尽管这是一个很大的丑陋:

新版本:

func (r *randomDataMaker) Read(p []byte) (n int, err error) {
    todo := len(p)
    offset := 0
    for {
        val := int64(r.src.Int63())
        for i := 0; i < 8; i++ {
            p[offset] = byte(val & 0xff)
            todo--
            if todo == 0 {
                return len(p), nil
            }
            offset++
            val >>= 8
        }
    }

    panic("unreachable")
}
Run Code Online (Sandbox Code Playgroud)

新基准:

BenchmarkRandomDataMaker      200000        251148 ns/op     796.34 MB/s
Run Code Online (Sandbox Code Playgroud)

编辑2

由于它是多余的,因此将转换中的掩码转换为字节.得到更快的交易:

BenchmarkRandomDataMaker      200000        231843 ns/op     862.64 MB/s
Run Code Online (Sandbox Code Playgroud)

(这比真正的工作叹息容易得多)

编辑3

今天在irc中出现了,所以我发布了一个库.此外,我的实际基准测试工具虽然对相对速度有用,但在报告中并不够准确.

我创建了randbo,您可以重复使用它来生成随机流,无论您需要它们.

  • 但是因为它是int63,所以每8个字节都有一个总是关闭的位,对吧? (2认同)

Eva*_*haw 15

这实际上有点偏向集合中的前8个字符(因为255不是倍数len(alphanum)),但是这将使你在那里大部分时间.

import (
    "crypto/rand"
)

func randString(n int) string {
    const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    var bytes = make([]byte, n)
    rand.Read(bytes)
    for i, b := range bytes {
        bytes[i] = alphanum[b % byte(len(alphanum))]
    }
    return string(bytes)
}
Run Code Online (Sandbox Code Playgroud)