在Go中生成一个长随机字符串的最快方法是什么? [英] What is the fastest way to generate a long random string in Go?

查看:603
本文介绍了在Go中生成一个长随机字符串的最快方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



na1dopW129T0anN28udaZ



或十六进制字符串:

8c6f78ac23b4a7b8c0182d

和更多的字符。

解决方案

这在我的盒子上大概有200MBps。

 类型randomDataMaker结构{
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
}

您只需使用 io.CopyN 来产生您想要的字符串。很明显,你可以调整字符集或其他任何方式。



这个模型的好处在于它只是一个 io.Reader 所以你可以使用它做任何事情。



测试如下:

pre > func BenchmarkRandomDataMaker(b * testing.B){
randomSrc:= randomDataMaker {rand.NewSource(1028890720402726901)}
for i:= 0;我< b.N; i ++ {
b.SetBytes(int64(i))
_,err:= io.CopyN(ioutil.Discard& randomSrc,int64(i))
if err!= nil {
b.Fatalf(错误复制在%v:%v,i,err)
}
}
}



在2.2GHz i7的一个核心上:

  BenchmarkRandomDataMaker 50000 246512 ns / op 202.83 MB / s 


$ b 编辑 p>

自从我编写基准测试以来,我认为自己会做出明显的改进(随机调用频率较低)。有1/8的兰德电话,运行速度提高了4倍,虽然这是一个很大的丑陋现象: 新版本:

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

panic(unreachable)
}

新基准:

  BenchmarkRandomDataMaker 200000 251148 ns / op 796.34 MB / s 

编辑2



由于它是多余的,因此将其转换为字节中的掩码。快得多:

  BenchmarkRandomDataMaker 200000 231843 ns / op 862.64 MB / s 

(这比真实的工作要容易得多)



<编辑3



今天在irc上发布了,于是我发布了一个图书馆。另外,我的实际基准测试工具虽然对相对速度有用,但在报告中不够准确。



我创建了 randbo ,您可以重复使用,随时随地产生随机流。


Like [a-zA-Z0-9] string:

na1dopW129T0anN28udaZ

or hexadecimal string:

8c6f78ac23b4a7b8c0182d

By long I mean 2K and more characters.

解决方案

This does about 200MBps on my box. There's obvious room for improvement.

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
}

You'd just use io.CopyN to produce the string you want. Obviously you could adjust the character set on the way in or whatever.

The nice thing about this model is that it's just an io.Reader so you can use it making anything.

Test is below:

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)
        }
    }
}

On one core of my 2.2GHz i7:

BenchmarkRandomDataMaker       50000        246512 ns/op     202.83 MB/s

EDIT

Since I wrote the benchmark, I figured I'd do the obvious improvement thing (call out to the random less frequently). With 1/8 the calls to rand, it runs about 4x faster, though it's a big uglier:

New version:

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")
}

New benchmark:

BenchmarkRandomDataMaker      200000        251148 ns/op     796.34 MB/s

EDIT 2

Took out the masking in the cast to byte since it was redundant. Got a good deal faster:

BenchmarkRandomDataMaker      200000        231843 ns/op     862.64 MB/s

(this is so much easier than real work sigh)

EDIT 3

This came up in irc today, so I released a library. Also, my actual benchmark tool, while useful for relative speed, isn't sufficiently accurate in its reporting.

I created randbo that you can reuse to produce random streams wherever you may need them.

这篇关于在Go中生成一个长随机字符串的最快方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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