什么是产生在很长的随机字符串的最快方法?(What is the fastest way to ge

2019-08-01 05:56发布

像[A-ZA-Z0-9]字符串:

na1dopW129T0anN28udaZ

或十六进制字符串:

8c6f78ac23b4a7b8c0182d

长我的意思是2K和多个字符。

Answer 1:

这确实对我的盒子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
}

你只是用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)
        }
    }
}

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

BenchmarkRandomDataMaker       50000        246512 ns/op     202.83 MB/s

编辑

自从我写的标杆,我想我会做明显改善的事情(不经常调出该随机)。 随着1/8调用兰特,它运行约快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")
}

新基准:

BenchmarkRandomDataMaker      200000        251148 ns/op     796.34 MB/s

编辑2

拿出掩蔽中投字节,因为它是多余的。 得到了一个很好的交易速度快:

BenchmarkRandomDataMaker      200000        231843 ns/op     862.64 MB/s

(这是这么多比真正的工作更容易叹息

编辑3

这在今天的IRC来了,所以我发布了一个图书馆。 另外,我的实际基准测试工具,而对于相对速度是有用的,是不是在其报告不够准确。

我创建randbo ,您可以重复产生随机流,无论你可能需要他们。



Answer 2:

您可以使用Go包uniuri来生成随机字符串(或查看源代码,看看他们是如何做)。 你要使用:

func NewLen(length int) string

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

或者,要指定一组使用的字符:

func NewLenChars(length int, chars []byte) string


Answer 3:

这实际上是对在一组前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)
}


Answer 4:

这里没有偏见埃文肖的回答再次合作对字符串的前8个字符。 请注意,它使用大量昂贵的big.Int操作,以便可能不是那么快! 答案是加密强虽然。

它采用rand.Int做出完全正确的大小的整len(alphanum) ** n ,然后做什么是一个有效的基本转换成基len(alphanum)

目前几乎可以肯定这将涉及保持一个更小的剩余时间和添加随机字节根据需要进行更好的算法。 这将摆脱对昂贵的长整数运算。

import (
    "crypto/rand"
    "fmt"
    "math/big"
)

func randString(n int) string {
    const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    symbols := big.NewInt(int64(len(alphanum)))
    states := big.NewInt(0)
    states.Exp(symbols, big.NewInt(int64(n)), nil)
    r, err := rand.Int(rand.Reader, states)
    if err != nil {
        panic(err)
    }
    var bytes = make([]byte, n)
    r2 := big.NewInt(0)
    symbol := big.NewInt(0)
    for i := range bytes {
        r2.DivMod(r, symbols, symbol)
        r, r2 = r2, r
        bytes[i] = alphanum[symbol.Int64()]
    }
    return string(bytes)
}


Answer 5:

如果你想生成加密的安全随机字符串,我建议你看看这个页面 。 这里是一个辅助函数读取n从您的操作系统的随机源随机字节,然后使用这些字节base64encode它。 需要注意的是字符串的长度会比大n因为BASE64的。

package main

import(
    "crypto/rand"
    "encoding/base64"
    "fmt"
)

func GenerateRandomBytes(n int) ([]byte, error) {
    b := make([]byte, n)
    _, err := rand.Read(b)
    if err != nil {
        return nil, err
    }

    return b, nil
}

func GenerateRandomString(s int) (string, error) {
    b, err := GenerateRandomBytes(s)
    return base64.URLEncoding.EncodeToString(b), err
}

func main() {
    token, _ := GenerateRandomString(32)
    fmt.Println(token)
}


Answer 6:

我做了一些基准和达斯汀的randbo包是我见过最快的。 我folked,并做出一些优化,所以它的速度更快,现在: GitHub上



文章来源: What is the fastest way to generate a long random string in Go?
标签: string random go