2009-10-07 7 views
5

Ich habe Probleme mit der Klasse Random in .NET, ich bin eine Thread-Sammlung implementieren, die gut funktioniert, bis auf ein kleineres Detail. Die Sammlung ist ein Skip list und die von Ihnen vertrauten wissen, dass ich für jeden eingefügten Knoten eine neue Höhe erzeugen muss, die <= CurrentMaxHeight+1 ist, hier ist der Code, den ich dazu verwende (ich weiß, dass es sehr ineffizient ist, aber es funktioniert und das ist meine Hauptpriorität jetzt) ​​Problem mit Random und Threads in .NET

int randomLevel() 
{ 
    int height = 1; 

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

    return height; 
} 

Mein Problem hier ist, dass ich manchmal bekomme immer nur 1 von diesen zurück für mehrere tausend Elemente in einer Reihe, die die Leistung der Sprungliste tötet. Die Chance für 10.000 Elemente, aus dieser Methode nur 1 zu generieren, scheint sehr gering (passiert ziemlich konsequent).

Ich gehe davon So (erraten), dass es ein Problem mit dem in irgendeine Weise Random Objekt ist, aber ich weiß nicht wirklich, wo um zu graben zu beginnen. Also wende ich mich Stackoverflow zu, um zu sehen, ob jemand eine Idee hat?

bearbeiten

Die RND-Variable wird SkipList<T> in der Klasse deklariert, und es ist aus mehreren Fäden zugegriffen wird (jeder Thread ruft .Add auf die Sammlung und Hinzufügen Anrufe .randomLevel)

+0

Wo wird 'rnd' deklariert? – ChrisF

+0

ist der randomlevel() aus einem separaten Thread aufgerufen? – Benny

+0

hinzugefügt Erklärung für Klarheit, es ist einmal erklärt und dann aus mehreren verschiedenen Threads aufgerufen. – thr

Antwort

4

Versuchen lock das Random Objekt.

int RandomLevel() 
{ 
    int height = 1; 

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

    return height; 
} 

Es kann ein Problem mit Kollisionen sein, wenn mehrere Threads das Random Objekt zur gleichen Zeit zugreifen, und das Saatgut möglicherweise beschädigt zu werden. Ich kann keinen Einblick darauf geben, was speziell passieren könnte, aber nach MSDN, Instanz Mitglieder der Random Typ sind nicht garantiert thread-safe, so scheint ein lock in jedem Fall aufgerufen werden.

+0

sollten Sie es auf diese Weise sperren: double d; Sperre (rnd) d = rnd.NextDouble(); das ist bessere Leistung – Benny

+1

Das Sperren der gesamten While-Schleife scheint eine etwas schlechte Idee. –

+1

Benny: Ich zweifle nicht an dir, aber interessiert dich warum? Meiner Meinung nach würde es eine schlechtere Leistung bringen, da ich den Lockvorgang mehrmals durchführen muss. – thr

1

Es sieht so aus, als ob Ihre Schleife weniger als die Hälfte der Zeit läuft - ist das wonach Sie suchen (wenn eine zufällige Zahl zwischen 0 und 1> 0,5 ist?) "öfter als Sie erwarten - mindestens die Hälfte der Zeit, es ist nicht einmal die Schleife läuft, die Höhe erhöht - es setzt nur die Höhe auf 1, ändert es nicht und gibt dann" 1 ". Ich bin nicht Ich bin mir nicht zu gut mit dem Arbeiten mit Zufallszahlen vertraut, aber ist es möglich, dass Sie ein Seeding-Problem haben? Wenn Sie das Objekt Random nicht zufällig zufallsberechnen, kann es einen vorhersehbaren Strom von Zahlen zurückgeben, anstelle von Zufallszahlen, die das Verhalten möglicherweise nicht verursachen Ihr seht hier, aber etwas, das in Betracht gezogen werden könnte.

3

Ich würde nicht die gesamte While-Schleife sperren. Sperren Sie einfach die rnd.NextDouble() -Aufrufe.

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; 
} 

Obwohl, wenn Leistung eine Überlegung ist, dass ich beiden Lösungen sicherlich vergleichen würde, wie könnte es ein Unterschied in der Single-Threaded vs. multithreaded Leistung.