Random number generator only generating one random number
    有以下功能:   
| 12
 3
 4
 5
 6
 
 | //Function to get random number
public static int RandomNumber(int  min, int  max)
{ 
    Random random = new  Random();
    return  random.Next( min, max);
} | 
   我叫它:   
| 12
 3
 
 | 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().Next((int)0xFFFF, (int)0xFFFFFF) % 256);不会产生比.Next(0, 256)更好的"随机"数。
- 您可能会发现这个Nuget包很有用。它提供了一个静态的Rand.Next(int, int)方法,该方法提供对随机值的静态访问,而不锁定或陷入种子重用问题。
 
	 
每次执行new Random()时,都会使用时钟进行初始化。这意味着在一个紧密的循环中,你会多次得到相同的值。您应该保留单个Random实例,并在同一实例上继续使用Next。
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | //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实现了这些方法中的第一种(和更简单的方法);然而,另一种方法可能是:
| 12
 
 | private static readonly ThreadLocal< Random>  appRandom
     = new  ThreadLocal< Random>(() => new  Random()); | 
这是每个线程的,所以不需要同步。
		
		
- 在这种情况下,我不确定这是否是答案,因为问题表明,当代码的这段附近没有断点时,函数工作正常。当然,我同意他应该使用一个随机对象的实例,但我认为这并不能回答他的问题。
- @约翰-仅仅是想让他保持在视线中就够难了(主要是作为中间距离的一个点)。
- 一般来说,所有静态方法都应该是线程安全的,因为很难保证多个线程不会同时调用它。通常不需要使实例(即非静态)方法具有线程安全性。
- hmm,相反,我认为实例方法需要更多的同步,因为大多数情况下,它们使用在中定义的对象的外部状态,而静态方法使用在不同(可能是并行)方法调用之间不共享的局部变量(基于堆栈)。所以我认为在这个特殊的情况下,同步可能是可以的(因为它使用一个共享资源),但我不会将其作为一般的最佳实践规则。
- @Florin-两者之间没有"基于堆栈"的区别。静态字段和"外部状态"一样多,绝对会在调用方之间共享。对于实例,不同的线程很可能有不同的实例(一个公共模式)。使用statics,可以保证它们都共享(不包括[threadstatic])。
- 为什么多个线程调用静态"randomnumber"方法会导致错误?
- @格多伦,你有错误吗?"锁"应该可以防止线程在这里相互绊倒…
- 不。。。我一点也没有出错,也没有使用lock。你能在答题框里再详细说明一下需要什么吗?
- @你的意思是:为什么这里需要lock?
- 应添加来自msdn的此行"此类型的任何公共静态(在VisualBasic中共享)成员都是线程安全的。任何实例成员都不能保证线程安全。"谢谢!
- @gdoron也看到了"社区内容"中的"随机不线程安全"——混乱的内部状态是非常糟糕的
- @MarcGravell使用ThreadLocal方法,如果两个线程同时访问appRandom,那么两个线程产生相同序列的风险是否仍然存在?或者线程的某些属性对生成的序列有贡献吗?
- @脚本从无到有,我想是的;如果这很重要,你可以一直有一个同步的主服务器Random……P
- 你为什么不能用lock(random)?
- @如果物体从未公开暴露:你可以。(非常理论上的)风险是其他线程正在以您不期望的方式锁定它。
- 我使用了锁机制,经过数百万次迭代,生成的唯一随机数是0。使用ThreadLocal解决了问题。理论上,锁应该工作得很好。但是在多次迭代之后每次都会出错。谢谢
- @斯米伦,我觉得这不太可能;一个重复会很有趣。
- @斯米隆,很可能你只是在锁外随意使用。锁定并不能阻止所有对您所锁定内容的访问——它只是确保同一实例上的两个lock语句不会同时运行。因此,只有当所有的random.Next()呼叫都在lock (syncObject)内时,lock (syncObject)才有帮助。如果您描述的场景确实发生在正确使用lock的情况下,那么它也极有可能发生在单线程场景中(例如,Random被巧妙地破坏)。
- 我在最近的一个项目(fungenerators.com/random/number)上遇到了类似的问题,尽管它使用的是PHP。结果发现其中一个包含的PHP类以错误的方式初始化了随机生成器的种子。所以它也可能是代码之外的东西。
 
	 
为了便于在整个应用程序中重用,静态类可能会有所帮助。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | 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; } }
} | 
然后可以使用静态随机实例和代码,例如
| 1
 | StaticRandom.Instance.Next(1, 100); | 
Mark的解决方案可能非常昂贵,因为它每次都需要同步。
我们可以使用线程特定的存储模式来绕过同步的需要:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 
 | 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);
    }
} | 
测量这两个实现,您应该看到一个显著的区别。
		
		
- 锁是非常便宜的,当他们没有竞争…即使有争议,我也希望"现在就用数字做点什么"代码在最有趣的场景中降低锁的成本。
- 同意,这解决了锁定问题,但对于一个小问题来说,这不是一个非常复杂的解决方案吗:您需要编写"两"行代码来生成一个随机数,而不是一个。读一行简单的代码真的值得吗?
- +1使用一个额外的全局Random实例来获取种子是一个不错的主意。还请注意,可以使用.NET 4中引入的ThreadLocal类进一步简化代码(Phil也在下面写到)。
 
	 
我的回答是:
重申正确的解决方案:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | namespace mySpace
{
    public static class  Util
    {
        private static  rnd = new  Random();
        public static int  GetRandom()
        {
            return  rnd.Next();
        }
    }
} | 
所以你可以打电话给:
| 1
 | var i = Util.GetRandom(); | 
贯穿始终。
如果您严格地需要一个真正的无状态静态方法来生成随机数,那么您可以依赖一个Guid。
| 12
 3
 4
 5
 6
 7
 
 | public static class Util{
 public static int GetRandom()
 {
 return Guid.NewGuid().GetHashCode();
 }
 }
 | 
它会慢一点,但比Random.Next更随机,至少从我的经验来看。
但不是:
| 1
 | new Random( Guid.NewGuid().GetHashCode()).Next(); | 
不必要的对象创建会使它变慢,特别是在循环下。
永远不会:
它不仅速度慢(在循环中),而且随机性…嗯,据我说不是很好。
		
		
- 我不同意guid的情况。随机类实现了统一的分布。在guid中不是这样的。guid的目标是唯一的,而不是均匀分布的(它的实现大部分时间是基于一些硬件/机器属性,这与…随机性)。
- @作为一个,我不确定。它是我们讨论的guid的散列值,而不是guid本身。而且很随意。你测试过这两个吗?我发现与Random.Next的碰撞更多。第二,MS不再基于硬件属性生成guid。
- 如果您不能证明guid生成的一致性,那么将其作为随机的使用是错误的(散列将是距离一致性的另一步)。同样,碰撞也不是问题:碰撞的均匀性是。关于guid的生成不再在硬件上了,我要去rtfm,我的坏(有参考吗?)
- @askolein我不需要证明guid生成的一致性,正如我所说的,重复一遍,guid的散列。.NET guid的GetHashCode基于guid的字符串表示,而不是数字本身(无论如何都是不可能的),而且据我测试,它是随机的。不可能显示出一些可预测的特征。如果散列是离统一性又一步的话,这不是一件好事吗?在随机讨论中,一致性是一件好事吗?或者我读错了你的"一致性"?
- 对"随机"有两种理解:1。缺少图案或2。在概率分布描述的进化过程中缺乏模式(2包含在1中)。您的guid示例在案例1中是正确的,而不是在案例2中。相反,Random类与case 2(因此,case 1也一样)匹配。如果您不在第2种情况下,您只能将Random的用法替换为Guid+Hash。案例1可能足够回答这个问题,然后,你的Guid+Hash就可以了。但没有清楚地说(附:这件制服)
- 我认为使用guid+hash作为种子,然后使用random可以解决案例1和2。这就是我需要的,它不是一个时间依赖的发电机。
- @作为Kolein的一部分测试数据,我通过ent(fourmilab.ch/random)运行了几批Random和Guid.NewGuid().GetHashCode(),两者都是随机的。new Random(Guid.NewGuid().GetHashCode())也可以工作,使用同步的"主"Random来为"子"Random生成种子。当然,这取决于您的系统如何生成guid——对于我的系统来说,它们是相当随机的,而对于其他系统,它甚至可能是加密随机的。所以现在Windows或MS SQL似乎很好。但Mono和/或Mobile可能不同。
- @六安,我没想到,但好吧…非常有趣。谢谢你的信息。
- 在guid和随机数之间有一个细微的区别。guid被设计为尽可能独特,但不一定是随机的。虽然理论上可以发生碰撞(即两次获得相同的guid),但发生碰撞的可能性应该非常小。它们在概念上与顺序整数相同,但其设计目的是在"值空间"中提供(合理的)均匀分布,而不是递增整数。随机数可以也应该产生碰撞。对于介于1和10之间的随机整数,您将得到相同的数字,每十次两次。
- @正如我之前在评论中所说的,edb虽然guid(一个大数字)是唯一的,但是.NET中guid的GetHashCode是从其字符串表示中派生出来的。根据我的喜好,输出是随机的。
- @纳法尔-我不同意这一点。这里重要的区别是guid应该是唯一的,没有碰撞(可能是随机的),而随机数应该有碰撞,例如系列5 2 2 7 4 5是"随机的",但有重复的数字。
- 不要依赖guid。guid在任何可能的意义上都不应该被用作随机的。它是独一无二的,独一无二的,独一无二的。
 
	 
我宁愿使用以下类生成随机数:
| 12
 3
 
 | byte[] random;
System.Security.Cryptography.RNGCryptoServiceProvider  prov = new System.Security.Cryptography.RNGCryptoServiceProvider(); 
prov.GetBytes( random); | 
		
		
- 我不是低落的选民之一,但请注意,标准PNRG确实服务于真正的需要,即能够重复复制已知种子的序列。有时真正的加密RNG的纯粹成本太高了。有时需要加密RNG。可以说,马是为课程而生。
- 根据文档,这个类是线程安全的,所以这对它是有利的。
- 两个随机字符串的概率是多少?如果字符串只有3个字符,我想这很有可能发生,但是如果255个字符的长度是可能有相同的随机字符串,或者保证从算法中不会发生这种情况呢?
 
	 
1)正如Marc Gravell所说,尝试使用一个随机生成器。把它添加到构造函数中总是很酷的:System.Environment.TickCount。
2)一个提示。假设您想要创建100个对象,并且假设每个对象都应该有自己的随机生成器(如果您在很短的时间内计算随机数的负载,这很方便)。如果要在循环中执行此操作(生成100个对象),可以这样做(以确保完全随机性):
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | 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); | 
干杯。
		
		
- 我会把System.Environment.TickCount移出循环。如果在迭代过程中循环,那么将有两个项目初始化为相同的种子。另一种选择是以不同的方式组合TickCount和I(例如System.Environment.TickCount<<8+I)
- 如果我理解正确:你的意思是,它可能发生,"system.environment.tickcount+i"可能产生相同的值吗?
- 编辑:当然,循环中不需要有滴答数。我的坏处:
- 默认的Random()构造函数无论如何都调用Random(Environment.TickCount)。
 
	 
每次执行时
| 1
 | Random random = new  Random (15); | 
如果你成百上千万次执行它并不重要,你将永远使用相同的种子。
如果你使用
| 1
 | Random random = new  Random (); | 
如果黑客猜到了种子,并且你的算法与你的系统的安全性相关,你会得到不同的随机数序列,你的算法就被破坏了。我是你处决穆特的。在此构造函数中,种子由系统时钟指定,如果在很短的时间(毫秒)内创建了多个实例,则它们可能具有相同的种子。
如果你需要安全的随机数,你必须使用该类
System.Security.Cryptography.RNGCryptoServiceProvider
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | 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);
} | 
用途:
| 1
 | int randomNumber = Next(1,100); | 
		
		
- 除非你自己指定种子,否则这不是真的。
- 修理好了。正如你所说,谢谢,如果总是指定相同的种子,那么总是会生成相同的随机数序列。在我的答案中,如果您总是使用相同的种子,那么我引用带有参数的构造函数。随机类只生成伪随机数。如果有人发现您在算法中使用了什么种子,它可能会损害算法的安全性或随机性。使用rngCryptoServiceProvider类,您可以安全地拥有随机数。我已经改正了,非常感谢你的改正。
 
	 
像这样声明随机类变量:
| 12
 3
 4
 
 |     Random r = new  Random();
    // ... Get three random numbers.
    //     Here you'll get numbers from 5 to 9 
    Console.WriteLine( r.Next(5 , 10)); | 
如果每次从列表中获得不同的随机数,请使用
| 1
 | r.Next(StartPoint,EndPoint) //Here end point will not be included | 
每次申报一次。
有很多解决方案,这里有一个:如果你只想要数字,删除字母,方法会收到一个随机的结果长度。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | 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);
 }
 |