2010-09-21 8 views
-1

La réponse acceptée à this question, et une discussion similaire au travail aujourd'hui m'a amené à s'interroger sur quelque chose.Numéros aléatoires et stockage local thread

La question portait sur la façon de générer en toute sécurité des nombres aléatoires dans un programme multithread. La réponse acceptée préconise l'utilisation du stockage local des threads, créant ainsi un générateur de nombres aléatoires par thread. Je me demande si c'est vraiment une bonne idée. Supposons que deux threads démarrent en même temps (ce qui est tout à fait possible sur un système multicœur) et que tous deux appellent le constructeur par défaut Random pour créer et initialiser un générateur de nombres aléatoires dans le stockage local de threads. Comme ils n'ont pas passé un paramètre de graine, Random utilise l'heure du système comme graine. Donc, les deux générateurs de nombres aléatoires ont été initialisés avec la même graine. Ils généreront tous les deux la même séquence de nombres aléatoires.

Étant donné que ces threads sont alloués à partir du pool de threads, vous ne pouvez pas associer un objet particulier à un thread particulier. Ou, dans le cas de la question référencée ci-dessus, vous ne pouvez pas garantir quel thread de pool exécutera la requête suivante. Alors, imaginez que les éléments suivants se produit:

At startup, two requests come in simultaneously. 
Two threads are created, each initializing a random number generator with the same seed. 

Each thread generates three random numbers. They will be identical in both threads. 

Next request comes in. It's assigned to thread #1. 
It generates a random number and exits. 

Some period of time elapses. 

Next request comes in. It's assigned to thread #2. 
It generates the same random number that thread #1 did just a while ago. 

Cela pourrait se poursuivre indéfiniment, même si je doute que ce serait ping-ponging tout à fait mal. Le fait est que les deux threads ont le même PRNG et la probabilité de répéter une séquence est très élevée. Je comprends que le P dans PRNG signifie "pseudo", mais c'est un peu beaucoup.

Je pense qu'il est tout à fait possible que plusieurs threads initialisent une instance Random avec la même valeur de départ. Si cela arrive, alors le "caractère aléatoire" d'au moins certaines choses dans l'application va en souffrir. Les implications de cela, bien sûr, dépendent de l'application. Ce que je ne sais pas, c'est que si les PRNG sont initialisés avec des graines différentes, est-ce que cela rend la séquence vue par un client plus aléatoire, moins aléatoire, ou à peu près la même chose? Autrement dit, si je devais écrire:

var rnd1 = new Random(123); 
var rnd2 = new Random(654); 
for (int i = 0; i < OneMillion; ++i) 
{ 
    numbers.Add(rnd1.Next()); 
numbers.Add(rnd2.Next()); 
} 

Est-ce que la séquence de chiffres que je produis plus ou moins aléatoire que si je devais simplement générer deux millions de l'une des PRNGs?

+0

Est-ce un problème pour votre application si, à chaque passage, vous générez la même séquence de nombres aléatoires? –

+0

Parlez-vous de C#? – sje397

+0

@Nader: La question est plus théorique que pratique, car je n'ai pas vraiment d'application particulière en tête. Mais disons que la réponse à votre question est oui. –

Répondre

1

Le niveau de caractère aléatoire doit être être approximativement le même, puisque les deux séries sont générées par le same algorithm.

Comment définissez-vous le caractère aléatoire? Si une série semble plus aléatoire ou non peut très bien dépendre de l'utilisateur, et ce que l'application fait avec la série de chiffres. Si vous êtes préoccupé par la même graine utilisée pour plusieurs générateurs de nombres aléatoires, vous pouvez toujours graver tous vos générateurs de nombres aléatoires à partir de la séquence générée par un autre générateur unique. De cette façon, au moins votre point de départ initial est quelque peu arbitraire.

+0

Merci. Mon "instinct" me dit qu'ils devraient être à peu près les mêmes. Je suppose que je devrais écrire du code pour tester cela (en utilisant l'estimation d'entropie). J'espérais que quelqu'un avait la réponse. Dans la mesure où plusieurs threads génèrent des nombres aléatoires, dans la situation que je décris, je préférerais utiliser un seul PRNG protégé par un verrou plutôt qu'une solution TLS. –

+0

Peut-être que c'est une autre question SO: "Qu'est-ce que l'estimation d'entropie nous dit sur le caractère aléatoire de la classe Random, avec des graines variées" :) Comme pour les PRNG simples/multiples, un seul PRNG protégé par un verrou est sensé. Déplacer pour utiliser plusieurs est vraiment une décision de performance. –

1

Les nombres générés sont aussi aléatoires que la graine que vous avez fournie. Si deux threads se retrouvent avec la même graine, ils auront exactement la même séquence de nombres "aléatoires".

Pour éviter cela, utilisez la synchronisation pour vous assurer que chaque générateur de nombres aléatoires stockés TLS reçoit une graine unique. Il existe d'autres façons de s'assurer que les graines sont uniques, sans dormir, mais c'est un moyen simple utile pour la démonstration.

Une autre option, à mon avis, une meilleure option, est d'utiliser un générateur de nombres aléatoires et de synchroniser les appels. Tout le monde s'inquiète de la synchronisation causant des différences de performances mais si vous générez des centaines de générateurs de nombres aléatoires une milliseconde, la synchronisation n'ajoutera aucune dégradation notable des performances (sur mon ordinateur portable je peux obtenir et libérer un verrou 17 000 fois une milliseconde).

+0

Merci, Sam, mais je sais comment éviter le problème. Je me demandais plus si 1) c'est un problème; et 2) quelle taille d'un problème. –

+1

Je suis d'accord avec votre réponse éditée: oubliez TLS et utilisez simplement un verrou. Le verrou, à moins qu'il ne soit contesté, se trouve dans le voisinage de 50 nanosecondes sur mon poste de travail. Et si 50 nanosecondes sont importantes, alors vous avez probablement un problème de performances beaucoup plus important que vous devez résoudre. –

+0

@Jim Mischel, d'après votre question, il semblait que vous demandiez si deux générateurs de nombres aléatoires seraient aléatoires quand ils recevraient la même graine. –

Questions connexes