Eu tenho a seguinte função:
//Function to get random number
public static int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
Como eu chamo isso:
byte[] mac = new byte[6];
for (int x = 0; x < 6; ++x)
mac[x] = (byte)(Misc.RandomNumber((int)0xFFFF, (int)0xFFFFFF) % 256);
Se eu passo esse loop com o depurador durante o tempo de execução, recebo valores diferentes (que é o que eu quero). No entanto, se eu colocar um ponto de interrupção duas linhas abaixo desse código, todos os membros da mac
matriz terão valor igual.
Por que isso acontece?
new Random().Next((int)0xFFFF, (int)0xFFFFFF) % 256);
não deu qualquer melhores números "aleatórios" que.Next(0, 256)
Rand.Next(int, int)
método que dá acesso estática para valores aleatórios sem bloquear ou que correm para o problema reutilização de sementesRespostas:
Toda vez que você faz
new Random()
isso é inicializado usando o relógio. Isso significa que, em um circuito fechado, você obtém o mesmo valor várias vezes. Você deve manter uma única instância aleatória e continuar usando Next na mesma instância.Editar (ver comentários): por que precisamos de um
lock
aqui?Basicamente,
Next
vai mudar o estado interno daRandom
instância. Se fizermos isso ao mesmo tempo a partir de vários encadeamentos, você poderá argumentar "acabamos de tornar o resultado ainda mais aleatório", mas o que realmente estamos fazendo é potencialmente violar a implementação interna e também podemos começar a obter os mesmos números de threads diferentes, o que pode ser um problema - e talvez não. A garantia do que acontece internamente é o problema maior; desdeRandom
que não faça nenhuma garantia de segurança de linha. Portanto, existem duas abordagens válidas:Random
instâncias diferentes por threadQualquer um pode ficar bem; mas mutex uma instância única de vários chamadores ao mesmo tempo está apenas causando problemas.
O
lock
atinge a primeira (e mais simples) dessas abordagens; no entanto, outra abordagem pode ser:isso é por thread, para que você não precise sincronizar.
fonte
lock (syncObject)
só ajudará se todas asrandom.Next()
chamadas também estiverem dentrolock (syncObject)
. Se o cenário que você descreve ocorrer mesmo com olock
uso correto , também é extremamente provável que ocorra em um cenário de thread único (por exemplo,Random
está sutilmente quebrado).Para facilitar a reutilização em todo o aplicativo, uma classe estática pode ajudar.
Você pode usar e usar instância aleatória estática com código como
fonte
A solução de Mark pode ser bastante cara, pois precisa ser sincronizada sempre.
Podemos contornar a necessidade de sincronização usando o padrão de armazenamento específico do encadeamento:
Meça as duas implementações e você verá uma diferença significativa.
fonte
Random
instância global adicional para obter a semente é uma boa ideia. Observe também que o código pode ser simplificado ainda mais usando aThreadLocal<T>
classe introduzida no .NET 4 (como Phil também escreveu abaixo ).Minha resposta daqui :
Apenas reiterando a solução certa :
Então você pode ligar para:
em toda parte.
Se você precisar estritamente de um método estático verdadeiro sem estado para gerar números aleatórios, poderá confiar em a
Guid
.Vai ser um pouco mais lento, mas pode ser muito mais aleatório do que
Random.Next
, pelo menos da minha experiência.Mas não :
A criação desnecessária de objetos vai torná-lo mais lento, especialmente em um loop.
E nunca :
Não só é mais lento (dentro de um loop), sua aleatoriedade é ... bem, não é muito boa de acordo comigo.
fonte
Random
classe corresponde ao caso 2 (portanto, também ao caso 1). Você só pode substituir o usoRandom
pelo seuGuid+Hash
se você não estiver no caso 2. O caso 1 provavelmente é suficiente para responder à pergunta e, em seguida, o seuGuid+Hash
trabalho está correto. Mas isso não é dito claramente (ps: esse uniforme ) #Random
eGuid.NewGuid().GetHashCode()
através do Ent ( fourmilab.ch/random ) e ambos são igualmente aleatórios.new Random(Guid.NewGuid().GetHashCode())
funciona tão bem quanto o uso de um "mestre" sincronizadoRandom
para gerar sementes para "filhos"Random
. É claro que depende de como o seu sistema gera Guids - para o meu sistema, eles são bastante aleatórios e, em outros, pode até ser cripto-aleatório. Então, o Windows ou o MS SQL parecem bons hoje em dia. Mono e / ou celular podem ser diferentes, no entanto.GetHashCode
o Guid no .NET é derivado de sua representação em cadeia. A saída é bastante aleatória para o meu gosto.Prefiro usar a seguinte classe para gerar números aleatórios:
fonte
1) Como Marc Gravell disse, tente usar UM gerador aleatório. É sempre legal adicionar isso ao construtor: System.Environment.TickCount.
2) Uma dica. Digamos que você queira criar 100 objetos e suponha que cada um deles tenha seu próprio gerador aleatório (útil se você calcular LOADS de números aleatórios em um período muito curto de tempo). Se você fizer isso em um loop (geração de 100 objetos), poderá fazer o seguinte (para garantir a aleatoriedade total):
Felicidades.
fonte
Random()
construtor padrão chamaRandom(Environment.TickCount)
assim mesmoToda vez que você executa
Não importa se você o executar milhões de vezes, sempre usará a mesma semente.
Se você usar
Você obtém uma sequência numérica aleatória diferente, se um hacker adivinhar a semente e seu algoritmo estiver relacionado à segurança do seu sistema - seu algoritmo está quebrado. Eu você executa mult. Nesse construtor, a semente é especificada pelo relógio do sistema e, se várias instâncias são criadas em um período muito curto de tempo (milissegundos), é possível que elas tenham a mesma semente.
Se você precisar de números aleatórios seguros, deverá usar a classe
Uso:
fonte
It does not matter if you execute it millions of times, you will always use the same seed.
Isso não é verdade, a menos que você mesmo especifique a semente.Apenas declare a variável da classe Random assim:
se você deseja obter um número aleatório diferente de cada vez da sua lista, use
Cada vez, declarando
Random r = new Random()
uma vez.fonte
new Random()
ele, usa o relógio do sistema, mas se você chamar esse código inteiro duas vezes seguidas antes que o relógio mude, você obterá o mesmo número aleatório. Esse é o objetivo das respostas acima.Existem muitas soluções, eis uma: se você deseja que apenas o número apague as letras e o método receba aleatoriamente e o comprimento do resultado.
fonte
Random
instância, mas ainda espera que o chamador crie uma instância compartilhada. Se o chamador criar uma nova instância a cada vez e o código for executado duas vezes antes do relógio mudar, você obterá o mesmo número aleatório. Portanto, essa resposta ainda faz suposições que podem ser errôneas.