다음과 같은 기능이 있습니다.
//Function to get random number
public static int RandomNumber(int min, int max)
{
Random random = new Random();
return random.Next(min, max);
}
내가 그것을 부르는 방법 :
byte[] mac = new byte[6];
for (int x = 0; x < 6; ++x)
mac[x] = (byte)(Misc.RandomNumber((int)0xFFFF, (int)0xFFFFFF) % 256);
런타임 동안 디버거를 사용하여 루프를 수행하면 다른 값을 얻습니다 (원하는 값). 그러나 중단 점을 해당 코드 아래에 두 줄로두면 mac
배열 의 모든 멤버 가 동일한 값을 갖습니다.
왜 그런 일이 발생합니까?
답변
할 때마다 new Random()
시계를 사용하여 초기화됩니다. 이것은 타이트한 루프에서 같은 값을 여러 번 얻는다는 것을 의미합니다. 단일 임의 인스턴스를 유지 하고 동일한 인스턴스 에서 다음 을 계속 사용해야 합니다.
//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);
}
}
편집 (의견 참조) : 왜 lock
여기에 필요한 가요?
기본적으로 인스턴스 Next
의 내부 상태를 변경하려고 Random
합니다. 여러 스레드에서 동시에 그렇게하면 “결과를 더욱 무작위로 만들었습니다”라고 주장 할 수 는 있지만 실제로 수행중인 작업은 내부 구현을 깨뜨릴 가능성이 있으며 동일한 숫자를 얻을 수도 있습니다. 다른 스레드에서 문제 가 될 수도 있고 아닐 수도 있습니다. 내부적으로 일어나는 일에 대한 보장은 더 큰 문제입니다. 스레드 안전성을 보장 Random
하지 않기 때문 입니다. 따라서 두 가지 유효한 접근 방식이 있습니다.
- 다른 스레드에서 동시에 액세스하지 못하도록 동기화
Random
스레드 당 다른 인스턴스 사용
어느 쪽이든 괜찮을 수 있습니다. 그러나 동시에 여러 호출자 의 단일 인스턴스를 뮤텍스 화하는 것은 문제를 요구합니다.
는 lock
이러한 방법의 첫 번째 (간단) 달성; 그러나 다른 접근 방식은 다음과 같습니다.
private static readonly ThreadLocal<Random> appRandom
= new ThreadLocal<Random>(() => new Random());
이것은 스레드 별이므로 동기화 할 필요가 없습니다.
답변
응용 프로그램 전체에서 쉽게 재사용 할 수 있도록 정적 클래스가 도움이 될 수 있습니다.
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; } }
}
그런 다음 정적 랜덤 인스턴스를 다음과 같은 코드와 함께 사용할 수 있습니다
StaticRandom.Instance.Next(1, 100);
답변
Mark의 솔루션은 매번 동기화해야하기 때문에 상당히 비쌀 수 있습니다.
스레드 별 스토리지 패턴을 사용하여 동기화 필요성을 해결할 수 있습니다.
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);
}
}
두 가지 구현을 측정하면 큰 차이가 나타납니다.
답변
내 대답은 여기에서 :
올바른 솔루션을 반복 하십시오 .
namespace mySpace
{
public static class Util
{
private static rnd = new Random();
public static int GetRandom()
{
return rnd.Next();
}
}
}
그래서 당신은 전화 할 수 있습니다 :
var i = Util.GetRandom();
전체적으로.
난수를 생성 하기 위해 진정한 stateless 정적 메소드가 꼭 필요한 경우에 의존 할 수 있습니다 Guid
.
public static class Util
{
public static int GetRandom()
{
return Guid.NewGuid().GetHashCode();
}
}
그것은 조금 느리게 될 것이지만Random.Next
적어도 내 경험에서 보다 훨씬 더 무작위 일 수 있습니다 .
그러나 아닙니다 :
new Random(Guid.NewGuid().GetHashCode()).Next();
불필요한 객체 생성은 특히 루프에서 느리게 만듭니다.
그리고 결코 :
new Random().Next();
속도가 느릴뿐만 아니라 (루프 내에서) 무작위성은 … 나에게 따르면 좋지 않습니다 ..
답변
차라리 다음 클래스를 사용하여 난수를 생성합니다.
byte[] random;
System.Security.Cryptography.RNGCryptoServiceProvider prov = new System.Security.Cryptography.RNGCryptoServiceProvider();
prov.GetBytes(random);
답변
1) Marc Gravell이 말했듯이 ONE random-generator를 사용해보십시오. 생성자에 System.Environment.TickCount를 추가하는 것이 항상 좋습니다.
2) 하나의 팁. 100 개의 객체를 만들고 각 객체에 자체 랜덤 생성기가 있어야한다고 가정합니다 (매우 짧은 기간에 임의의 숫자의 LOADS를 계산하는 경우 유용합니다). 루프 (100 개의 객체 생성)에서이 작업을 수행하면 다음과 같이 수행 할 수 있습니다 (완전한 임의성을 보장하기 위해).
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);
건배.
답변
실행할 때마다
Random random = new Random (15);
수백만 번 실행해도 중요하지 않으며 항상 동일한 시드를 사용합니다.
당신이 사용하는 경우
Random random = new Random ();
해커가 시드를 추측하고 알고리즘이 시스템의 보안과 관련되어 있으면 알고리즘이 손상되면 다른 임의의 숫자 시퀀스를 얻습니다. 당신은 복수를 실행합니다. 이 생성자에서 시드는 시스템 시계에 의해 지정되며 매우 짧은 시간 (밀리 초) 내에 여러 인스턴스가 생성되면 동일한 시드를 가질 수 있습니다.
안전한 임의의 숫자가 필요한 경우 클래스를 사용해야합니다
System.Security.Cryptography.RNGCryptoServiceProvider
public static int Next(int min, int max)
{
if(min >= max)
{
throw new ArgumentException("Min value is greater or equals than Max value.");
}
byte[] intBytes = new byte[4];
using(RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
rng.GetNonZeroBytes(intBytes);
}
return min + Math.Abs(BitConverter.ToInt32(intBytes, 0)) % (max - min + 1);
}
용법:
int randomNumber = Next(1,100);