https://www.cnblogs.com/jackcheblog/p/7417632.html 这里列出几个常用但,效果一般的随机数生成方式;
最大的陷阱可能还是来自我们的random
上面的文章,写的很一般,很一般;
具体的还是看我们c# in depth 中的一篇关于random的文章;http://csharpindepth.com/Articles/Chapter12/Random.aspx
The parameterless constructor for Random
takes the current date and time as the seed
然后,我再写一些完整的测试代码;
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApplication70 { /// <summary> /// 错误的单例模式; /// </summary> public static class RandomHelper { //这样的话,能够保证,高并发下的单例=》Random,但是不能保证,高并发下的时间搓,也就是我们的seed子不同; //所以这种做法依然有一定的风险; //这样写,智能保证 random 在 RandomHelper 中是线程安全的; private static Random random; private static readonly object _locker = new object();//低并发的情况下,用lock,简单粗暴,不出错 public static Random GetThreadSafeRandom { get { if (random == null) { lock (_locker) { if (random == null) { return new Random(); //不存在每次都生成一个实例;错误 } } } return random; } } } /// <summary> /// 正确的单例模式; /// </summary> public static class RandomHelperV1 { //这样的话,能够保证,高并发下的单例=》Random,但是不能保证,高并发下的时间搓,也就是我们的seed子不同; //所以这种做法依然有一定的风险; //这样写,智能保证 random 在 RandomHelper 中是线程安全的; private static Random random; private static readonly object _locker = new object();//低并发的情况下,用lock,简单粗暴,不出错 public static Random GetThreadSafeRandom { get { if (random == null) { lock (_locker) { if (random == null) { random= new Random(); //不存在每次都生成一个实例;错误 return random; } } } return random; } } } /// <summary> /// 也就是要解决两个问题;一个是for循环,生成的是相同的实例;因为seed是基于本机系统的事件;使用同一个seed,生词的随机数就是一样滴呀; /// 第二个就是在高并发下, /// </summary> class Program { /// <summary> /// 关于random 经典的问题; /// </summary> static void Test0() { for (int i = 0; i < 10; i++) { Random random = new Random(); int result= random.Next(0,10); //重复,非随机; 最本质的问题,还是,系统时间的问题; Console.WriteLine(result); } } /// <summary> /// 单例模式能够解决问题吗? 这个只是为了记录一下:错误的单例模式写法; /// 窝草,单例模式,用错了;窝草; /// </summary> static void Test1() { for (int i = 0; i < 10; i++) { int result=RandomHelper.GetThreadSafeRandom.Next(0,10); //虽然只有一个实例,但是还是生产了重复的东西; //调用方法是对的,是我们的单例模式的实现错了; Console.WriteLine(result); } } /// <summary> /// 这样能解决问题;but web 天生多线程;能够保证在多线程下,不会生成同一个random吗? /// </summary> static void Test11() { Random random = new Random(); //确保random先初始化 for (int i = 0; i < 10; i++) { int result = random.Next(0, 10); Console.WriteLine(result); } } /// <summary> /// 采用单例模式,but=>这样就利用到lock,保证了多线程单例,但是,并发性就降低了; /// 有没有更好的解决方案呢; /// </summary> static void Test2() { for (int i = 0; i < 10; i++) { int result = RandomHelperV1.GetThreadSafeRandom.Next(0, 10); //虽然只有一个实例,但是还是生产了重复的东西; Console.WriteLine(result); } } static void TestTick() { for (int i = 0; i < 10; i++) { int result = Environment.TickCount; Thread.Sleep(1); Console.WriteLine(result); } } /// <summary> /// 第一次重视错误的; /// </summary> static void TestRandomTick() { int _seed=Environment.TickCount; //这样做也是于是舞步滴呀; for (int i = 0; i < 10; i++) { //int _seed=Environment.TickCount; //这样做也是于是舞步滴呀; Random random = new Random(Interlocked.Increment(ref _seed)); int result = random.Next(0, 10); //重复,非随机; 最本质的问题,还是,系统时间的问题; Console.WriteLine(result); } } static void TestRandomCount() { for (int i = 0; i < 10; i++) { Random random = new Random(i);//每次输入不同的种子;保证每一次的种子不一样; int result = random.Next(0, 10); Console.WriteLine(result); } } static void Main(string[] args) { Console.WriteLine("--------------------test0"); Test0(); Thread.Sleep(100); Console.WriteLine("--------------------test1"); Test1(); Console.WriteLine("--------------------test11"); Test11(); //Thread.Sleep(100); //这样的话,Test11 和 Test2 生成了相同的随机数;窝草; Console.WriteLine("--------------------test2"); Test2(); Console.WriteLine("--------------------TestTick"); TestTick(); Console.WriteLine("--------------------TestRandomTick"); TestRandomTick(); Console.WriteLine("--------------------TestRandomCount"); TestRandomCount(); //to be continuted.... Console.ReadLine(); } } }
然后,较好的一种解决方案;
/// <summary> /// 随机数提供者 /// 保证每个线程使用自身的随机数产生器 /// </summary> public static class RandomProvider { private static int _seed = Environment.TickCount; private static readonly ThreadLocal<Random> RandomWrapper = new ThreadLocal<Random>(() => new Random(Interlocked.Increment(ref _seed)) ); /// <summary> /// 获取线程相关的随机数产生器 /// </summary> /// <returns></returns> public static Random GetThreadRandom() { return RandomWrapper.Value; } }
to do list....