2009-10-07 11 views
5

Ho problemi con la classe Random in .NET, sto implementando una raccolta con thread che funziona bene, tranne che per un dettaglio più piccolo. La collezione è una Skip list e chi di voi ha dimestichezza sa che per ogni nodo inserito ho bisogno di generare una nuova altezza che sia <= CurrentMaxHeight+1, ecco il codice che sto usando per farlo (so che è molto inefficiente, ma funziona e questo è la mia priorità principale ora)Problema con casuale e discussioni in .NET

int randomLevel() 
{ 
    int height = 1; 

    while(rnd.NextDouble() >= 0.5 && height < MaxHeight) 
    ++height; 

    return height; 
} 

il mio problema è che a volte continuo a ricevere solo 1 indietro da questo per diverse migliaia di elementi di fila che uccide le prestazioni della skip list. La possibilità per 10.000 elementi di generare solo 1 da questo metodo di fila, sembra molto sottile (accade abbastanza coerentemente).

Così sto supponendo (indovinare) che c'è un problema con l'oggetto Random in qualche modo, ma io non so davvero da dove cominciare a scavare intorno. Quindi mi rivolgo a StackOverflow per vedere se qualcuno ha un'idea?

Modifica

La variabile RND viene dichiarata nella classe SkipList<T>, e vi si accede da diversi thread (ogni thread chiama .Add sulla raccolta e aggiungere chiamate .randomLevel)

+0

Dove è dichiarato 'rnd'? – ChrisF

+0

è il randomlevel() chiamato da un thread separato? – Benny

+0

aggiunta dichiarazione per chiarezza, è dichiarata una volta e quindi chiamata da diversi thread differenti. – thr

risposta

4

Prova lock l'oggetto Random.

int RandomLevel() 
{ 
    int height = 1; 

    lock(rnd) 
    { 
     while(rnd.NextDouble >= 0.5 && height < MaxHeight) height++; 
    } 

    return height; 
} 

Ci può essere un problema con le collisioni quando più thread accedono all'oggetto Random, allo stesso tempo, e il seme potrebbe essere venire corrotto. Non riesco a fornire informazioni su cosa potrebbe essere nello specifico, ma in base allo MSDN, i membri di istanza del tipo Random non sono garantiti come thread-safe, quindi è richiesto un lock in ogni caso.

+0

si dovrebbe bloccare in questo modo: doppio d; lock (rnd) d = rnd.NextDouble(); questa è una prestazione migliore – Benny

+1

Il blocco dell'intero ciclo while sembra una cattiva idea. –

+1

Benny: Non sto dubitando di te, ma ti interessa spiegare perché? Nella mia mente darebbe prestazioni peggiori dal momento che ho bisogno di fare l'operazione di blocco più volte. – thr

1

Sembra che il ciclo venga eseguito meno della metà del tempo richiesto, è quello che stai cercando (quando un numero casuale compreso tra 0 e 1 è> 0,5? Questo potrebbe spiegare perché stai ricevendo "1 "più spesso di quanto ti aspetteresti - almeno la metà delle volte, non è nemmeno in esecuzione il ciclo che incrementa l'altezza - imposta solo l'altezza a 1, non la modifica, quindi restituisce" 1 ". conoscere le skip list, quindi questo potrebbe essere intenzionale, ma ho pensato di chiederlo.

Non ho molta familiarità con il lavoro con numeri casuali, ma è possibile che tu abbia un problema di semina? 'Non randomizzare l'oggetto Random quando lo installi, può restituire un flusso prevedibile di numeri, invece di quelli che sono veramente casuali. stai vedendo qui, ma qualcosa da considerare in futuro.

3

Non vorrei bloccare l'intero ciclo while. Basta bloccare le chiamate rnd.NextDouble().

int RandomLevel() 
{ 
    int height = 1; 
    double newRand; 

    lock(rnd) { newRand = rnd.NextDouble(); } 

    while(newRand >= 0.5 && height < MaxHeight) 
    { 
    height++; 
    lock(rnd) { newRand = rnd.NextDouble(); } 
    } 

    return height; 
} 

Anche se le prestazioni sono una considerazione, certamente confrontare entrambe le soluzioni, come ci potrebbe essere una differenza di single threaded vs. prestazioni multithread.