J'ai la fonction suivante:
//Function to get random number
public static int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
Comment je l'appelle:
byte[] mac = new byte[6];
for (int x = 0; x < 6; ++x)
mac[x] = (byte)(Misc.RandomNumber((int)0xFFFF, (int)0xFFFFFF) % 256);
Si j'étape cette boucle avec le débogueur pendant l'exécution, j'obtiens des valeurs différentes (ce que je veux). Cependant, si je mets un point d'arrêt deux lignes en dessous de ce code, tous les membres du mac
tableau ont la même valeur.
Pourquoi cela se produit-il?
new Random().Next((int)0xFFFF, (int)0xFFFFFF) % 256);
ne donne pas de meilleurs nombres "aléatoires" que.Next(0, 256)
Rand.Next(int, int)
méthode statique qui fournit un accès statique à des valeurs aléatoires sans se bloquer ni rencontrer le problème de réutilisation de la graineRéponses:
Chaque fois que vous le faites,
new Random()
il est initialisé à l'aide de l'horloge. Cela signifie que dans une boucle serrée, vous obtenez souvent la même valeur. Vous devez conserver une seule instance aléatoire et continuer à utiliser Next sur la même instance.Edit (voir commentaires): pourquoi avons-nous besoin d'un
lock
ici?Fondamentalement,
Next
va changer l'état interne de l'Random
instance. Si nous le faisons en même temps à partir de plusieurs threads, vous pourriez dire "nous venons de rendre le résultat encore plus aléatoire", mais ce que nous faisons en fait est potentiellement de casser l'implémentation interne, et nous pourrions également commencer à obtenir les mêmes chiffres à partir de différents threads, ce qui pourrait être un problème - et peut-être pas. La garantie de ce qui se passe en interne est le plus gros problème, cependant; carRandom
ne pas faire aucune garantie de fil de sécurité. Il existe donc deux approches valides:Random
instances par threadSoit peut être bien; mais mutexer une seule instance de plusieurs appelants en même temps ne fait que demander des ennuis.
Le
lock
réalise la première (et la plus simple) de ces approches; cependant, une autre approche pourrait être:c'est alors par thread, vous n'avez donc pas besoin de synchroniser.
la source
lock (syncObject)
cela n'aidera que si tous lesrandom.Next()
appels sont également à l'intérieurlock (syncObject)
. Si le scénario que vous décrivez se produit même avec unelock
utilisation correcte , il se produit également très probablement dans un scénario à un seul thread (par exemple, ilRandom
est subtilement cassé).Pour faciliter la réutilisation dans toute votre application, une classe statique peut vous aider.
Vous pouvez utiliser puis utiliser une instance aléatoire statique avec du code tel que
la source
La solution de Mark peut être assez coûteuse car elle doit être synchronisée à chaque fois.
Nous pouvons contourner le besoin de synchronisation en utilisant le modèle de stockage spécifique au thread:
Mesurez les deux implémentations et vous devriez voir une différence significative.
la source
Random
instance globale supplémentaire pour obtenir la graine est une bonne idée. Notez également que le code peut être encore simplifié en utilisant laThreadLocal<T>
classe introduite dans .NET 4 (comme Phil l'a également écrit ci-dessous ).Ma réponse d' ici :
Réitérant simplement la bonne solution :
Vous pouvez donc appeler:
tout au long de.
Si vous avez strictement besoin d'une véritable méthode statique sans état pour générer des nombres aléatoires, vous pouvez vous fier à a
Guid
.Ça va être un peu plus lent, mais peut être beaucoup plus aléatoire que
Random.Next
, du moins d'après mon expérience.Mais pas :
La création inutile d'objets va le ralentir, surtout sous une boucle.
Et jamais :
Non seulement c'est plus lent (à l'intérieur d'une boucle), son caractère aléatoire est ... enfin pas vraiment bon selon moi ..
la source
Random
classe correspond au cas 2 (donc, le cas 1 aussi). Vous ne pouvez remplacer l'utilisation deRandom
par votre queGuid+Hash
si vous n'êtes pas dans le cas 2. Le cas 1 est probablement suffisant pour répondre à la question, puis, toutGuid+Hash
fonctionne bien. Mais ce n'est pas dit clairement (ps: cet uniforme )Random
etGuid.NewGuid().GetHashCode()
via Ent ( fourmilab.ch/random ) et les deux sont de même aléatoires.new Random(Guid.NewGuid().GetHashCode())
fonctionne tout aussi bien, tout comme l'utilisation d'un "maître" synchroniséRandom
pour générer des graines pour les "enfants"Random
. Bien sûr, cela dépend de la façon dont votre système génère des guides - pour mon système, ils sont assez aléatoires, et pour d'autres, cela peut même être crypto-aléatoire. Windows ou MS SQL semble donc bien de nos jours. Mono et / ou mobile peuvent cependant être différents.GetHashCode
le Guid dans .NET est dérivé de sa représentation sous forme de chaîne. La sortie est assez aléatoire à mon goût.Je préfère utiliser la classe suivante pour générer des nombres aléatoires:
la source
1) Comme l'a dit Marc Gravell, essayez d'utiliser UN générateur aléatoire. C'est toujours cool d'ajouter cela au constructeur: System.Environment.TickCount.
2) Un conseil. Supposons que vous vouliez créer 100 objets et supposons que chacun d'eux ait son propre générateur aléatoire (pratique si vous calculez les CHARGES de nombres aléatoires en très peu de temps). Si vous le faisiez en boucle (génération de 100 objets), vous pourriez faire ça comme ça (pour assurer un caractère totalement aléatoire):
À votre santé.
la source
Random()
constructeur par défaut appelleRandom(Environment.TickCount)
quand mêmeChaque fois que vous exécutez
Peu importe que vous l'exécutiez des millions de fois, vous utiliserez toujours la même graine.
Si tu utilises
Vous obtenez une séquence de nombres aléatoires différente, si un pirate devine la graine et que votre algorithme est lié à la sécurité de votre système - votre algorithme est cassé. Si vous exécutez mult. Dans ce constructeur, la graine est spécifiée par l'horloge système et si plusieurs instances sont créées en très peu de temps (millisecondes), il est possible qu'elles aient la même graine.
Si vous avez besoin de nombres aléatoires sûrs, vous devez utiliser la classe
Usage:
la source
It does not matter if you execute it millions of times, you will always use the same seed.
Ce n'est pas vrai, sauf si vous spécifiez la graine vous-même.déclarez simplement la variable de classe aléatoire comme ceci:
si vous voulez obtenir un nombre aléatoire différent à chaque fois dans votre liste, utilisez
Chaque fois en déclarant
Random r = new Random()
une fois.la source
new Random()
il utilise l'horloge système, mais si vous appelez l'intégralité de ce code deux fois de suite avant que l'horloge ne change, vous obtiendrez le même nombre aléatoire. C'est tout l'intérêt des réponses ci-dessus.Il y a beaucoup de solutions, en voici une: si vous voulez seulement effacer les lettres et que la méthode reçoit un aléatoire et la longueur du résultat.
la source
Random
instance, mais vous vous attendez toujours à ce que l'appelant crée une instance partagée. Si l'appelant crée une nouvelle instance à chaque fois et que le code est exécuté deux fois avant le changement d'horloge, vous obtiendrez le même nombre aléatoire. Cette réponse émet donc toujours des hypothèses qui pourraient être erronées.