日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
如何正確的在C#中使用Random類-創(chuàng)新互聯(lián)

如何正確的在C# 中使用Random類?相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。

創(chuàng)新互聯(lián)建站專注于企業(yè)網(wǎng)絡(luò)營(yíng)銷推廣、網(wǎng)站重做改版、懷來(lái)網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、H5高端網(wǎng)站建設(shè)、商城網(wǎng)站建設(shè)、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站制作、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁(yè)設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為懷來(lái)等各大城市提供網(wǎng)站開(kāi)發(fā)制作服務(wù)。

Random類介紹

Random類一個(gè)用于產(chǎn)生偽隨機(jī) 數(shù)字的類。這里的偽隨機(jī)表示有隨機(jī)性但是可以基于算法模擬出隨機(jī)規(guī)律。

Random類的構(gòu)造方式有兩種。

  • Random r= new Random()。會(huì)以當(dāng)前系統(tǒng)時(shí)間作為默認(rèn)種子構(gòu)建一個(gè)隨機(jī)序列

  • Random r = new Random(unchecked((int)DateTime.Now.Ticks));。自定義一個(gè)種子,通常會(huì)使用時(shí)間Ticks。

隨機(jī)性保證

由于Random的偽隨機(jī) 性,所以如果多個(gè)Random隨機(jī)序列生成的時(shí)間間隔很短(官方說(shuō)法15ms內(nèi)),那么他們產(chǎn)生的隨機(jī)數(shù)會(huì)大概率相同。如下列代碼

 /// 
  /// 錯(cuò)誤的Random構(gòu)建。
  /// 
  public static void Bad_Random()
  {
    //正確做法應(yīng)當(dāng)將 Random構(gòu)建防止循環(huán)外。
    //Random創(chuàng)建間隔時(shí)間極短的情況下,隨機(jī)算法序列會(huì)基本一致,倒是隨機(jī)性也是一致的
    //var r = new Random();
    for (int i = 0; i < 10; i++)
    {
      var r = new Random();
      var val = r.Next(1, 100);
      Console.WriteLine(val);
    }
  }

運(yùn)行結(jié)果:

如何正確的在C# 中使用Random類

所以在生產(chǎn)中通??梢钥紤]將Random單例化,以保證其隨機(jī)算法的序列獨(dú)一性。這也是官方推薦的方式。

Instead of instantiating individual Random objects, we recommend that you create a single Random instance to generate all the random numbers needed by your app.

這個(gè)問(wèn)題在.net core下官方組件已對(duì)Random的構(gòu)建作優(yōu)化,所以上面的案例代碼如果放在.net core項(xiàng)目下運(yùn)行,你會(huì)發(fā)現(xiàn)可以正確的生成隨機(jī)數(shù)。有興趣的小伙伴可以自己嘗試一下。不過(guò)為了代碼的延續(xù)性,還是建議Random作為單例模式設(shè)計(jì)。

那么將Random設(shè)計(jì)為單例是否就解決了隨機(jī)性的問(wèn)題了呢,這時(shí)候就涉及到另外一個(gè)問(wèn)題,Random不是線程安全的。如下列代碼

  /// 
  /// 生成一個(gè)10位隨機(jī)數(shù)
  /// 設(shè)定了一定的復(fù)雜性,保證單線程下隨機(jī)數(shù)不重復(fù)
  /// 
  /// Random.
  /// 隨機(jī)數(shù).
  private static string GenerateRandomStr(Random random)
  {
    string source = "ABCDEFGHIKLMNOPQRTUVWXYZabcdefghiklmnopqrtuvwxyz";
    int length = 10;
    var list = Enumerable.Repeat(source, length)
       .Select(s => s[random.Next(s.Length)]).ToArray();
    return new string(list);
  }
  /// 
  /// 單線程基本可以保證性
  /// 
  public static void Good_Random_In_SingleThread()
  {
    //正確做法應(yīng)當(dāng)將 Random構(gòu)建防止循環(huán)外。
    //Random創(chuàng)建間隔時(shí)間極短的情況下,隨機(jī)算法序列會(huì)基本一致,倒是隨機(jī)性也是一致的
    var r = new Random();
    ConcurrentBag list = new ConcurrentBag();
    for (int i = 0; i < 20000; i++)
    {
      var val = GenerateRandomStr(r);
      list.Add(val);
    }

    Console.WriteLine($"單線程下重復(fù)數(shù)據(jù)有:{20000 - list.Distinct().Count()}");
  }

  /// 
  /// 多線程下的Random構(gòu)建。
  /// Bad案例,Random非線程安全
  /// 多線程高并發(fā)情況下,會(huì)出現(xiàn)概率重復(fù)
  /// 
  public static void Bad_Random_In_MultThreads()
  {
    var r = new Random(unchecked((int)DateTime.Now.Ticks));
    ConcurrentBag list = new ConcurrentBag();

    var t1 = Task.Run(() =>
    {
      for (int i = 0; i < 10000; i++)
      {
        var val = GenerateRandomStr(r);
        list.Add(val);
      }
    });

    var t2 = Task.Run(() =>
    {
      for (int i = 0; i < 10000; i++)
      {
        var val = GenerateRandomStr(r);
        list.Add(val);
      }
    });

    Task.WaitAll(t1, t2);

    Console.WriteLine($"線程1和線程2的重復(fù)數(shù)據(jù)有:{20000 - list.Distinct().Count()}");
  }

運(yùn)行結(jié)果:

如何正確的在C# 中使用Random類

這種重復(fù)率在生產(chǎn)環(huán)境上是不可接受的。那么產(chǎn)生的原因是什么呢?根源還是在偽隨機(jī)線程不安全 上。我們可以想象下,一個(gè)Random實(shí)例中基于隨機(jī)算法產(chǎn)生的一個(gè)隨機(jī)數(shù)序列,在單線程下pop出一個(gè)隨機(jī)數(shù),然后指向下一個(gè)隨機(jī)數(shù)。而在高并發(fā)的多線程情況下,指向下一個(gè)隨機(jī)數(shù)的動(dòng)作還未完成時(shí),另一個(gè)線程又來(lái)請(qǐng)求pop,這樣相同的隨機(jī)數(shù)被重復(fù)pop了。

網(wǎng)上有很多多線程下Random的解決方案,我查閱了一些感覺(jué)都不是很好。以下是我的解決方案。用到了ThreadLocal 。這個(gè)類詳細(xì)的作用大家可以自己去查閱,這里大家只需要知道這個(gè)類可以保證它包含的對(duì)象只能線程內(nèi)獨(dú)享。簡(jiǎn)單說(shuō),同一類型對(duì)象 每個(gè)線程都獨(dú)有一個(gè)Random實(shí)例互不影響。

 //利用ThreadLocal 實(shí)現(xiàn)每個(gè)線程下Random獨(dú)有
  //再通過(guò)seed原子性變更,保證每個(gè)Random的seed不同而生成的隨機(jī)數(shù)列也不同
  private static int seed = 100;
  private static ThreadLocal threadLocal = new ThreadLocal(() => new Random(Interlocked.Increment(ref seed)));

  /// 
  /// 多線程下的Random構(gòu)建。
  /// 
  public static void Good_Random_In_MultThreads()
  {
    ConcurrentBag list = new ConcurrentBag();

    var t1 = Task.Run(() =>
    {
      for (int i = 0; i < 10000; i++)
      {
        var val = GenerateRandomStr(threadLocal.Value);
        list.Add(val);
      }
    });

    var t2 = Task.Run(() =>
    {
      for (int i = 0; i < 10000; i++)
      {
        var val = GenerateRandomStr(threadLocal.Value);
        list.Add(val);
      }
    });

    Task.WaitAll(t1, t2);

    Console.WriteLine($"[ThreadLocal模式]線程1和線程2的重復(fù)數(shù)據(jù)有:{20000 - list.Distinct().Count()}");
  }

運(yùn)行結(jié)果:

如何正確的在C# 中使用Random類

由此可見(jiàn),基于ThreadLocal的特性,并區(qū)別了每個(gè)線程下的seed都不一樣,從而保證每個(gè)Random的隨機(jī)性也不行一樣。

那么到這里Random的隨機(jī)性問(wèn)題解決了嗎??

再深入思考下,對(duì)于集群部署情況,多臺(tái)服務(wù)器同時(shí)運(yùn)行,上述的Random隨機(jī)性能保證嗎?聰明的小伙伴應(yīng)該能想到在不同服務(wù)器上,由于初始seed相同,可能又導(dǎo)致Random的隨機(jī)性相同的情況發(fā)生。

那么解決方案也很簡(jiǎn)單,保證每臺(tái)服務(wù)器的初始seed不同即可。這里的解決方案很多,不限于機(jī)器編號(hào)、IP地址后幾位、啟動(dòng)時(shí)間(Environment.TickCount)等等。

看完上述內(nèi)容,你們掌握如何正確的在C# 中使用Random類的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!


文章名稱:如何正確的在C#中使用Random類-創(chuàng)新互聯(lián)
標(biāo)題路徑:http://www.dlmjj.cn/article/dosgii.html