c#随机数相关

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....

posted @ 2017-12-05 19:24  咕-咚  阅读(259)  评论(0)    收藏  举报