2013-10-09 4 views
32

Ok. Voici ce que je sais ça ne marchera pas:Manière correcte d'utiliser Random dans l'application multithread

int Rand() 
{ 
    //will return the same number over and over again 
    return new Random().Next(); 
} 

static Random rnd=new Random(); 

int Rand() 
{ 
    //if used like this from multiple threads, rnd will dissintegrate 
    //over time and always return 0 
    return rnd.Next(); 
} 

Cela fonctionne correctement, mais si elle est utilisée par plusieurs threads, l'utilisation du processeur va bien, ce que je ne veux pas, et que je pense n'est pas Donc, y a-t-il une classe aléatoire thread-safe pour C#, ou une meilleure façon de l'utiliser?

+2

Essayez un 'ThreadLocal '. 'private static readonly ThreadLocal rand = new ThreadLocal (() => new Random());' –

+7

@JeroenVannevel: Vous voudrez probablement randomiser les graines des instances 'Random', car sinon les threads démarrent en même temps obtiendrait la même séquence de nombres aléatoires. – dtb

+0

.. et de prendre une instance aléatoire statique globale verrouillée pour la graine des instances aléatoires ThreadLocal. – Ralf

Répondre

45

J'utilise quelque chose comme ceci:

public static class StaticRandom 
{ 
    static int seed = Environment.TickCount; 

    static readonly ThreadLocal<Random> random = 
     new ThreadLocal<Random>(() => new Random(Interlocked.Increment(ref seed))); 

    public static int Rand() 
    { 
     return random.Value.Next(); 
    } 
} 
+0

J'aime vraiment ça, ça fonctionne correctement, et lorsqu'il est utilisé en multithread, cet exemple est 10 fois plus rapide que la méthode de verrouillage! –

+0

Cela ne risque-t-il pas de produire un tas d'instances aléatoires avec la même graine, lorsque les threads sont créés et commencent à l'utiliser à peu près en même temps? –

+3

@EricJ. Non, car il utilise une graine incrémentée. –

5

Je pense que ce que vous voulez est ThreadStatic

[ThreadStatic] 
static Random rnd=new Random(); 

int Rand() 
{ 
    if (rnd == null) 
    { 
     rnd = new Random() 
    } 
    //Now each thread gets it's own version 
    return rnd.Next(); 
} 

De cette façon, chaque fil obtenir leur propre version de votre propriété rnd

La raison pour laquelle votre verrouillage augmentera l'utilisation du processeur est parce que tous les threads attendront sur ce point unique (ne devrait poser problème que si vous l'utilisez beaucoup)

[Mise à jour] J'ai corrigé l'initialisation. Comme quelqu'un l'a fait remarquer, cela laisse le fait que si vous démarrez plusieurs threads dans la même miliseconde, ils produiront les mêmes résultats.

+3

Selon cette réponse http://stackoverflow.com/a/18337158/1164966, «ThreadLocal » doit être préféré à '[ThreadStatic]' car il garantit que le champ est initialisé pour chaque thread. –

+0

Ou si vous n'aimez pas ThreadStatic, créez explicitement autant d'instances Random() que vous avez de theads. – Eiver

+3

C'est risqué quand même. Si vous commencez deux threads en succession rapide, leurs graines peuvent être les mêmes. – harold

12
readonly ThreadLocal<Random> random = 
    new ThreadLocal<Random>(() => new Random(GetSeed())); 

int Rand() 
{ 
    return random.Value.Next(); 
} 

static int GetSeed() 
{ 
    return Environment.TickCount * Thread.CurrentThread.ManagedThreadId; 
} 

(sans vergogne volé du commentaire de Jeroen Vannevel)

+0

Je n'ai pas honte d'upvote, premier arrivé, premier servi :) – AlexH

+2

Il n'y a pas de honte à améliorer les suggestions!;) –

+1

multiplier le temps avec l'ID de fil est stupide. Considérons les cas où l'un d'eux est un 0, ou même juste un pouvoir de deux. Et même si ce n'était pas un problème, générer une graine aléatoire de 31 bits pour chaque instance vous frappe encore plus dur avec le problème d'anniversaire que Alessandro. – CodesInChaos

1

Mon groupe a récemment examiné dans ce. Nous sommes arrivés à la conclusion que nous devrions utiliser un générateur de nombres aléatoires spécialement conçu pour prendre en charge l'informatique parallèle. Bibliothèque de générateurs de nombres aléatoires de Tina (http://numbercrunch.de/trng/) a une mise en œuvre stable, et un manuel avec une introduction théorique et des références à la littérature pertinente. Jusqu'à présent, nous en sommes très satisfaits.

+1

cela concerne C++, pas C#, mais utile quand même –

Questions connexes