2013-10-09 14 views
32

Ok. Ecco quello che so che non funziona:Modo corretto per utilizzare Casuale nell'applicazione 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(); 
} 

Ciò funzionerà correttamente, ma se usato da più thread, l'utilizzo della CPU va verso l'alto, che io non voglio, e che credo non sia necessaria:

int Rand() 
{ 
    lock(rnd) 
    { 
     return rnd.Next(); 
    } 
} 

Quindi, c'è una classe Random thread-safe per C#, o un modo migliore per usarlo?

+2

Provare un 'ThreadLocal '. 'statico privato readonly ThreadLocal rand = new ThreadLocal (() => new Random());' –

+7

@JeroenVannevel: Probabilmente vorrai randomizzare i semi delle istanze 'Random', perché altrimenti i thread partono allo stesso tempo otterrebbe la stessa sequenza di numeri casuali. – dtb

+0

.. e prendere un'istanza casuale statica bloccata globale per il seed delle istanze casuali di ThreadLocal. – Ralf

risposta

45

io uso qualcosa di simile:

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

Mi piace molto, funziona correttamente e, se utilizzato in multithread, questo esempio è 10 volte più veloce del metodo di blocco! –

+0

Questo rischio non produrrà un gruppo di istanze Casuali con lo stesso seme, quando i thread vengono creati e iniziano ad usarlo nello stesso tempo? –

+3

@EricJ. no, perché usa un seme incrementale. –

5

penso che quello che vuoi è 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(); 
} 

In questo modo ogni thread ottenere la propria versione della vostra proprietà RND

Il motivo per il vostro blocco aumenterà l'utilizzo della CPU è perché tutte le discussioni aspetteranno in quel punto singolo (dovrebbe essere un problema solo se lo si utilizza molto)

[Aggiornamento] Ho corretto l'inizializzazione. Come qualcuno ha sottolineato, lascia il fatto che se si avviano più thread nello stesso millisecondo, essi produrranno gli stessi risultati.

+3

In base a questa risposta http://stackoverflow.com/a/18337158/1164966, 'ThreadLocal ' è da preferire a '[ThreadStatic]' perché garantisce che il campo sia inizializzato per ogni thread. –

+0

Oppure, se non ti piace ThreadStatic, crea in modo esplicito tutte le istanze di Casuale() dei tuoni. – Eiver

+3

È comunque rischioso. Se inizi due thread in rapida successione, i loro semi possono essere gli stessi. – 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; 
} 

(spudoratamente rubato dal commento di Jeroen Vannevel)

+0

Non ho vergogna di andare avanti, prima è arrivato, primo servito :) – AlexH

+2

Non c'è da vergognarsi nel migliorare i suggerimenti!;) –

+1

moltiplicando il tempo con ID thread è sciocco. Considera i casi in cui uno di essi è uno 0, o anche solo un potere-di-due. E anche se questo non fosse un problema, generare un seme casuale a 31 bit per ogni istanza ti colpisce ancora di più con il problema del compleanno di Alessandro. – CodesInChaos

1

Il mio gruppo ha recentemente esaminato questo. Siamo giunti alla conclusione che dovremmo utilizzare un generatore di numeri casuali appositamente progettato per supportare il calcolo parallelo. La libreria del generatore di numeri casuali di Tina (http://numbercrunch.de/trng/) ha un'implementazione stabile e un manuale con un'introduzione teorica e riferimenti alla letteratura pertinente. Finora, ne siamo molto soddisfatti.

+1

questo riguarda C++, non C#, ma comunque utile –

Problemi correlati