Estou tentando gerar uma seqüência aleatória no Go e aqui está o código que escrevi até agora:
package main
import (
"bytes"
"fmt"
"math/rand"
"time"
)
func main() {
fmt.Println(randomString(10))
}
func randomString(l int) string {
var result bytes.Buffer
var temp string
for i := 0; i < l; {
if string(randInt(65, 90)) != temp {
temp = string(randInt(65, 90))
result.WriteString(temp)
i++
}
}
return result.String()
}
func randInt(min int, max int) int {
rand.Seed(time.Now().UTC().UnixNano())
return min + rand.Intn(max-min)
}
Minha implementação é muito lenta. A propagação usando time
traz o mesmo número aleatório por um certo tempo, portanto o loop itera repetidamente. Como posso melhorar meu código?
Respostas:
Cada vez que você define a mesma semente, obtém a mesma sequência. Então, é claro, se você estiver definindo a semente no tempo em um ciclo rápido, provavelmente a chamará com a mesma semente muitas vezes.
No seu caso, como você está chamando seu
randInt
função até ter um valor diferente, você está aguardando a hora (conforme retornada pelo Nano) mudar.Quanto a todas as bibliotecas pseudo-aleatórias , você deve definir a semente apenas uma vez, por exemplo, ao inicializar seu programa, a menos que precise especificamente reproduzir uma determinada sequência (o que geralmente é feito apenas para depuração e teste de unidade).
Depois disso, basta ligar
Intn
para obter o próximo número inteiro aleatório.Mova a
rand.Seed(time.Now().UTC().UnixNano())
linha da função randInt para o início da principal e tudo será mais rápido.Observe também que acho que você pode simplificar sua construção de strings:
fonte
rand.Seed(...)
à funçãoinit()
.init()
é chamado automaticamente antesmain()
. Observe que você não precisa ligarinit()
demain()
!math/rand
não é criptograficamente seguro de qualquer maneira. Se isso é um requisito,crypto/rand
deve ser usado.Não entendo por que as pessoas estão semeando com um valor de tempo. Na minha experiência, isso nunca foi uma boa ideia. Por exemplo, embora o relógio do sistema seja talvez representado em nanossegundos, a precisão do relógio do sistema não é de nanossegundos.
Este programa não deve ser executado no playground Go, mas se você o executar na máquina, obterá uma estimativa aproximada do tipo de precisão que você pode esperar. Eu vejo incrementos de cerca de 1000000 ns, então incrementos de 1 ms. São 20 bits de entropia que não são usados. Enquanto isso, os bits altos são na maioria constantes.
O grau em que isso é importante para você varia, mas você pode evitar as armadilhas dos valores das sementes baseadas no relógio simplesmente usando a
crypto/rand.Read
fonte como para sua semente. Isso fornecerá a qualidade não determinística que você provavelmente está procurando em seus números aleatórios (mesmo que a própria implementação seja limitada a um conjunto de seqüências aleatórias distintas e determinísticas).Como uma nota lateral, mas em relação à sua pergunta. Você pode criar o seu próprio
rand.Source
usando esse método para evitar o custo de ter bloqueios protegendo a origem. orand
funções do utilitário de pacotes são convenientes, mas também usam travas sob o capô para impedir que a fonte seja usada simultaneamente. Se você não precisar, pode evitá-lo criando o seuSource
e usá-lo de maneira não simultânea. Independentemente disso, você NÃO deve realizar uma nova propagação do gerador de números aleatórios entre as iterações, nunca foi projetado para ser usado dessa maneira.fonte
apenas para descartá-lo para a posteridade: às vezes pode ser preferível gerar uma sequência aleatória usando uma sequência inicial de caracteres. Isso é útil se a string for inserida manualmente por um ser humano; excluindo 0, O, 1 e eu podemos ajudar a reduzir o erro do usuário.
e normalmente coloco a semente dentro de um
init()
bloco. Eles estão documentados aqui: http://golang.org/doc/effective_go.html#initfonte
-1
emrand.Intn(len(alpha)-1)
. Isso ocorre porquerand.Intn(n)
sempre retorna um número menor quen
(em outras palavras: de zero an-1
inclusivo).-1
inlen(alpha)-1
garantiria que o número 9 nunca fosse usado na sequência.OK por que tão complexo!
Isso é baseado no código do distro, mas adequado às minhas necessidades.
São seis (rands ints
1 =< i =< 6
)A função acima é exatamente a mesma coisa.
Espero que esta informação tenha sido útil.
fonte
3 5 2 5 4 2 5 6 3 1
rand.Intn()
, caso contrário, sempre obterá o mesmo número sempre que executar o programa.var bytes int
? Qual é a diferença de alterar o acimabytes = rand.Intn(6)+1
parabytes := rand.Intn(6)+1
? Ambos parecem funcionar para mim, é um deles sub-ideal por algum motivo?São nano segundos, quais são as chances de obter a mesma semente duas vezes.
De qualquer forma, obrigado pela ajuda, aqui está minha solução final com base em todas as informações.
fonte
what are the chances of getting the exact the exact same [nanosecond] twice?
Excelente. Tudo depende da precisão interna da implementação dos tempos de execução do golang. Mesmo que as unidades sejam nanossegundos, o menor incremento pode ser um milésimo de segundo ou até um segundo.Se o seu objetivo é apenas gerar um número aleatório, acho desnecessário complicá-lo com várias chamadas de função ou redefinir a semente toda vez.
O passo mais importante é chamar a função de semente apenas uma vez antes de realmente executar
rand.Init(x)
. Semente usa o valor de semente fornecido para inicializar a Origem padrão para um estado determinístico. Portanto, seria sugerido chamá-lo uma vez antes da chamada de função real para o gerador de números pseudo-aleatórios.Aqui está um código de exemplo criando uma sequência de números aleatórios
A razão pela qual eu usei o Sprintf é porque ele permite formatação simples de string.
Além disso, In
rand.Intn(7)
Intn retorna, como int, um número pseudo-aleatório não negativo em [0,7).fonte
@ [Denys Séguret] postou correto. Mas, no meu caso, preciso de novas sementes toda vez que estão abaixo do código;
Caso você precise de funções rápidas. Eu uso assim.
fonte
fonte
Pequena atualização devido a alterações na API do golang, omita .UTC ():
time.Now (). UTC () .UnixNano () -> time.Now (). UnixNano ()
fonte