CSharp - 随机号码生成器只生成一个随机数

  显示原文与译文双语对照的内容

我有以下功能:


//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);

如果在运行时使用调试器执行该循环,则会得到不同的值( 这就是我想要的) 。 但是,如果在代码下面的两行下放置一个断点,那么"苹果机"数组的所有成员都有相等的值。

为什么会发生这种情况?

时间:

每次执行 new Random() 时,它都使用时钟初始化。 这意味着在紧凑的循环中,你得到的值是相同的。 在同一 instance,你应该保持单一 Random 实例和一直用


//Function to get 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 确实 thread-safety的不作任何担保。 因此有两种有效的方法:

  • 同步使我们不能同时从不同的线程访问它
  • 每个线程使用不同的Random 实例

同时仅仅是要求输入trouble,也可以自己很好;但从多个callers.不断改变一个实例

lock 实现了这些方法的第一个( 更简单) ;然而,另一种方法可能是:


private static readonly ThreadLocal<Random> appRandom
 = new ThreadLocal<Random>(() => new Random());

这是 per-thread,所以你不需要同步。

标记的解决方案相当昂贵,因为它需要每次同步。

通过使用thread-specific存储模式,我们可以绕过同步的需求:



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


度量两个实现,你应该会看到显著差异。

良好的实践,你可以使用一个静态 helper 类,你可以在整个应用程序中使用它


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

我宁愿使用以下类生成随机数:


byte[] random;
System.Security.Cryptography.RNGCryptoServiceProvider prov = new System.Security.Cryptography.RNGCryptoServiceProvider();
prov.GetBytes(random);

我从的答案是:

只是再次重申: 正确的解决方案


namespace mySpace
{
 public static class Util
 {
 private static rnd = new Random();
 public static int GetRandom()
 {
 return rnd.Next();
 }
 }
}

你可以调用:


var i = Util.GetRandom();

全部贯穿整个。

在一个如果严格需要一个真正的无状态的静态方法随机数的产生,可以 rely.


public static class Util
{
 public static int GetRandom()
 {
 return Guid.NewGuid().GetHashCode();
 }
}

至少从我 experience, 有一点是一成略微降低性能,但是可以更为随意排列比 Random.Next,.

:


new Random(Guid.NewGuid().GetHashCode()).Next();

不必要的对象创建将使它变得更慢,尤其在循环下。

从不:

 
new Random().Next();

 

不仅是( 循环内) 较慢,它的随机性是。。 根据我的说法,这并不是很好。

1 ) 就像 Marc Gravell说的,试着使用一个 random-generator 。 将它添加到构造函数总是很酷: System.Environment.TickCount 。

2 ) 。假设你想要创建 100个对象,假设每个对象都有 its-own random-generator ( 如果在非常短的时间内计算随机数,则方便) 。 如果你在循环( 生成 100个对象) 中这么做,你可以这样做( 确保 fully-randomness ):


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

干杯。

有很多解决方案,这里有一个: 如果你只想要清除字母,则该方法会收到随机和结果长度。


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

...