Mam następującą funkcję:
//Function to get random number
public static int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
Jak to nazywam:
byte[] mac = new byte[6];
for (int x = 0; x < 6; ++x)
mac[x] = (byte)(Misc.RandomNumber((int)0xFFFF, (int)0xFFFFFF) % 256);
Jeśli uruchomię tę pętlę za pomocą debugera podczas uruchamiania, otrzymam różne wartości (to jest to, czego chcę). Jeśli jednak umieszczę punkt przerwania dwie linie poniżej tego kodu, wszyscy członkowie mac
tablicy mają równą wartość.
Dlaczego tak się dzieje?
new Random().Next((int)0xFFFF, (int)0xFFFFFF) % 256);
nie daje lepszych „losowych” liczb niż.Next(0, 256)
Rand.Next(int, int)
metodę statyczną , która zapewnia statyczny dostęp do losowych wartości bez blokowania lub problemów z ponownym użyciem materiału siewnegoOdpowiedzi:
Za każdym razem
new Random()
jest to inicjowane przy użyciu zegara. Oznacza to, że w ciasnej pętli dostajesz tę samą wartość wiele razy. Powinieneś zachować pojedyncze Losowe wystąpienie i dalej używać Dalej w tym samym wystąpieniu.Edytuj (patrz komentarze): dlaczego potrzebujemy
lock
tutaj?Zasadniczo
Next
zamierza zmienić wewnętrzny stanRandom
instancji. Jeśli zrobimy to w tym samym czasie z wielu wątków, to mógłby argumentować „my właśnie sprawiło, że jeszcze bardziej przypadkowy wynik”, ale co my właściwie robi potencjalnie zerwania wdrożenie wewnętrznego, a także moglibyśmy zacząć uzyskiwać te same numery z różnych wątków, co może być problemem - a może nie. Większe znaczenie ma jednak gwarancja tego, co dzieje się wewnętrznie; ponieważRandom
nie daje żadnych gwarancji bezpieczeństwa nici. Istnieją zatem dwa ważne podejścia:Random
instancji na wątekOba mogą być w porządku; ale muteksowanie pojedynczej instancji od wielu rozmówców w tym samym czasie to po prostu prośba o kłopoty.
lock
Osiąga pierwszy (i prostsze) tych metod; jednak innym podejściem może być:jest to następnie dla wątku, więc nie trzeba synchronizować.
źródło
lock (syncObject)
pomoże tylko wtedy, gdy wszystkierandom.Next()
połączenia są również wewnątrzlock (syncObject)
. Jeśli opisany przez Ciebie scenariusz ma miejsce nawet przy prawidłowymlock
użytkowaniu, niezwykle prawdopodobne jest również w scenariuszu jednowątkowym (np.Random
Jest subtelnie zepsuty).Aby ułatwić ponowne użycie w całej aplikacji, może pomóc klasa statyczna.
Następnie można użyć statycznej losowej instancji z kodem takim jak
źródło
Rozwiązanie Marka może być dość drogie, ponieważ wymaga synchronizacji za każdym razem.
Możemy ominąć potrzebę synchronizacji, stosując wzorzec przechowywania specyficzny dla wątku:
Zmierz obie implementacje i powinieneś zobaczyć znaczącą różnicę.
źródło
Random
instancji w celu uzyskania nasion jest dobrym pomysłem. Zauważ też, że kod można dodatkowo uprościć za pomocąThreadLocal<T>
klasy wprowadzonej w .NET 4 (jak Phil również napisał poniżej ).Moja odpowiedź stąd :
Powtarzam tylko właściwe rozwiązanie :
Możesz więc zadzwonić:
wszystko poprzez.
Jeśli do generowania liczb losowych potrzebujesz bezwzględnej metody statycznej bezstanowej , możesz polegać na
Guid
.To będzie odrobinę wolniejsze, ale może być znacznie bardziej przypadkowy niż
Random.Next
, przynajmniej z mojego doświadczenia.Ale nie :
Niepotrzebne tworzenie obiektów spowoduje spowolnienie, szczególnie w pętli.
I nigdy :
Nie tylko jest wolniejszy (wewnątrz pętli), ale jego losowość jest ... cóż, według mnie niezbyt dobra ...
źródło
Random
klasa pasuje do przypadku 2 (a więc również przypadku 1). Można wymienić tylko wykorzystanieRandom
przez twojąGuid+Hash
jeśli nie w przypadku 2. Przypadek 1 to chyba wystarczy, aby odpowiedzieć na pytanie, a następnie swojąGuid+Hash
karę działa. Ale nie jest wyraźnie powiedziane (ps: ten mundur )Random
iGuid.NewGuid().GetHashCode()
poprzez Ent ( fourmilab.ch/random ) i oba są podobnie losowe.new Random(Guid.NewGuid().GetHashCode())
działa równie dobrze, jak przy użyciu zsynchronizowanego „mistrza”Random
do generowania nasion dla „dzieci”Random
. Oczywiście zależy to od tego, jak twój system generuje Guids - dla mojego systemu są one dość losowe, a od innych może to być być nawet krypto-losowym. Tak więc Windows lub MS SQL wydaje się dziś w porządku. Mono i / lub telefony komórkowe mogą być jednak inne.GetHashCode
Guid w .NET pochodzi z jego reprezentacji łańcuchowej. Jak dla mnie, wynik jest dość losowy.Wolę użyć następującej klasy do generowania liczb losowych:
źródło
1) Jak powiedział Marc Gravell, spróbuj użyć JEDNEGO generatora losowego. Zawsze fajnie jest dodać to do konstruktora: System.Environment.TickCount.
2) Jedna wskazówka. Załóżmy, że chcesz utworzyć 100 obiektów i załóżmy, że każdy z nich powinien mieć własny generator losowy (przydatny, jeśli obliczasz ŁADUNKI liczb losowych w bardzo krótkim czasie). Jeśli zrobiłbyś to w pętli (generowanie 100 obiektów), możesz to zrobić w ten sposób (aby zapewnić pełną losowość):
Twoje zdrowie.
źródło
Random()
konstruktor iRandom(Environment.TickCount)
tak wywołujeZa każdym razem, gdy wykonujesz
Nie ma znaczenia, czy wykonasz to miliony razy, zawsze użyjesz tego samego ziarna.
Jeśli użyjesz
Otrzymujesz inną sekwencję liczb losowych, jeśli haker zgadnie ziarno, a twój algorytm jest związany z bezpieczeństwem twojego systemu - twój algorytm jest zepsuty. Ja wykonujesz mult. W tym konstruktorze ziarno jest określane przez zegar systemowy i jeśli w bardzo krótkim czasie (milisekundach) utworzonych zostanie kilka instancji, możliwe jest, że mogą mieć to samo ziarno.
Jeśli potrzebujesz bezpiecznych liczb losowych, musisz skorzystać z klasy
Stosowanie:
źródło
It does not matter if you execute it millions of times, you will always use the same seed.
To nie jest prawda, chyba że sam określisz ziarno.po prostu zadeklaruj zmienną klasy Losowej w następujący sposób:
jeśli chcesz uzyskać inną liczbę losową za każdym razem z listy, użyj
Za każdym razem, deklarując
Random r = new Random()
raz.źródło
new Random()
, używa zegara systemowego, ale jeśli wywołasz ten cały kod dwa razy z rzędu przed zmianą zegara, otrzymasz ten sam losowy numer. To jest sedno powyższych odpowiedzi.Istnieje wiele rozwiązań, tutaj jedno: jeśli chcesz tylko liczby, usuń litery, a metoda otrzyma losową i wynikową długość.
źródło
Random
instancji, ale nadal oczekujesz, że osoba dzwoniąca utworzy instancję udostępnioną. Jeśli dzwoniący tworzy nowe wystąpienie za każdym razem, a kod jest wykonywany dwukrotnie przed zmianą zegara, otrzymasz ten sam losowy numer. Tak więc ta odpowiedź wciąż przyjmuje założenia, które mogą być błędne.