Generator liczb losowych generuje tylko jedną liczbę losową
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 wykonam tę pętlę z debuggerem podczas wykonywania, otrzymam inne wartości (co jest tym, czego chcę). Jeśli jednak umieszczę punkt przerwania dwa wiersze poniżej tego kodu, wszyscy członkowie tablicy " mac " mają taką samą wartość.
Dlaczego tak się dzieje?7 answers
Za każdym razem, gdy robisz {[2] } jest inicjowana za pomocą zegara. Oznacza to, że w ciasnej pętli otrzymujesz tę samą wartość wiele razy. Należy zachować pojedynczą instancję Random
i używać Next
na tej samej instancji.
//Function to get a random number
private static readonly Random random = new Random();
private static readonly object syncLock = new object();
public static int RandomNumber(int min, int max)
{
lock(syncLock) { // synchronize
return random.Next(min, max);
}
}
Edit (Zobacz komentarze): po co nam lock
tutaj?
Zasadniczo, Next
zmieni stan wewnętrzny instancji Random
. Jeśli zrobimy to w tym samym czasie z wielu wątków, możesz argumentować " właśnie zrobiliśmy wynik jest jeszcze bardziej losowy", ale to, co robimy w rzeczywistości, potencjalnie łamie wewnętrzną implementację, a także możemy zacząć uzyskiwać te same liczby z różnych wątków, co może być problemem - a może nie. Gwarancja tego, co dzieje się wewnętrznie, jest jednak większym problemem; ponieważ Random
Nie daje jakiekolwiek gwarancje bezpieczeństwa wątku. Tak więc istnieją dwa ważne podejścia:
- synchronizować, abyśmy nie mieli do niego dostępu w ten sam czas z różnych wątków
- użyj różnych instancji
Random
na wątek
Albo może być w porządku; ale muteksowanie pojedynczej instancji od wielu wywołujących jednocześnie jest tylko pytaniem o kłopoty.
lock
osiąga pierwszy (i prostszy) z tych podejść; jednak inne podejście może być:
private static readonly ThreadLocal<Random> appRandom
= new ThreadLocal<Random>(() => new Random());
To jest na wątek, więc nie trzeba synchronizować.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-29 06:45:03
Dla ułatwienia ponownego użycia w całej aplikacji może pomóc Klasa statyczna.
public static class StaticRandom
{
private static int seed;
private static ThreadLocal<Random> threadLocal = new ThreadLocal<Random>
(() => new Random(Interlocked.Increment(ref seed)));
static StaticRandom()
{
seed = Environment.TickCount;
}
public static Random Instance { get { return threadLocal.Value; } }
}
Możesz użyć wtedy statycznej instancji losowej z kodem takim jak
StaticRandom.Instance.Next(1, 100);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-27 22:05:02
Rozwiązanie marka może być dość drogie, ponieważ wymaga synchronizacji za każdym razem.
Możemy obejść potrzebę synchronizacji za pomocą specyficznego dla wątku wzorca przechowywania:
public class RandomNumber : IRandomNumber
{
private static readonly Random Global = new Random();
[ThreadStatic] private static Random _local;
public int Next(int max)
{
var localBuffer = _local;
if (localBuffer == null)
{
int seed;
lock(Global) seed = Global.Next();
localBuffer = new Random(seed);
_local = localBuffer;
}
return localBuffer.Next(max);
}
}
Zmierz dwie implementacje, a zobaczysz znaczącą różnicę.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-23 11:26:10
Moja odpowiedź z tutaj :
Wystarczy powtórzyć właściwe rozwiązanie :
namespace mySpace
{
public static class Util
{
private static rnd = new Random();
public static int GetRandom()
{
return rnd.Next();
}
}
}
Więc możesz zadzwonić:
var i = Util.GetRandom();
/ Align = "left" /
Jeśli do generowania liczb losowych potrzebujesz statycznej metody True stateless, możesz polegać na Guid
.
public static class Util
{
public static int GetRandom()
{
return Guid.NewGuid().GetHashCode();
}
}
to będzie trochę wolniejsze, ale może być znacznie bardziej losowe niż Random.Next
, przynajmniej z mojego doświadczenia.
Ale Nie :
new Random(Guid.NewGuid().GetHashCode()).Next();
The niepotrzebne tworzenie obiektów spowoduje, że będzie wolniej, zwłaszcza pod pętlą.
Inigdy :
new Random().Next();
Nie dość, że jest wolniejszy (wewnątrz pętli), to jego losowość jest... według mnie niezbyt dobrze..Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:07
Wolałbym użyć następującej klasy do generowania liczb losowych:
byte[] random;
System.Security.Cryptography.RNGCryptoServiceProvider prov = new System.Security.Cryptography.RNGCryptoServiceProvider();
prov.GetBytes(random);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-22 17:43:17
1) Jak powiedział Marc Gravell, spróbuj użyć jednego generatora losowego. Zawsze fajnie jest dodać to do konstruktora: System.Środowisko.TickCount.
2) Jedna wskazówka. Załóżmy, że chcesz utworzyć 100 obiektów i załóżmy, że każdy z nich powinien mieć swój własny generator losowy (przydatne, jeśli obliczysz ładunki liczb losowych w bardzo krótkim okresie czasu). Jeśli chcesz to zrobić w pętli (generowanie 100 obiektów), możesz to zrobić w ten sposób (aby zapewnić pełna losowość):
int inMyRandSeed;
for(int i=0;i<100;i++)
{
inMyRandSeed = System.Environment.TickCount + i;
.
.
.
myNewObject = new MyNewObject(inMyRandSeed);
.
.
.
}
// Usage: Random m_rndGen = new Random(inMyRandSeed);
Zdrówko.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-25 17:24:34
Istnieje wiele rozwiązań, tutaj jeden: jeśli chcesz tylko numer Wymaż litery i metoda otrzymuje losową i długość wyniku.
public String GenerateRandom(Random oRandom, int iLongitudPin)
{
String sCharacters = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ123456789";
int iLength = sCharacters.Length;
char cCharacter;
int iLongitudNuevaCadena = iLongitudPin;
String sRandomResult = "";
for (int i = 0; i < iLongitudNuevaCadena; i++)
{
cCharacter = sCharacters[oRandom.Next(iLength)];
sRandomResult += cCharacter.ToString();
}
return (sRandomResult);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-04 05:13:31