欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C# Random類的正確應(yīng)用方法

 更新時間:2020年11月26日 10:23:13   作者:gt1987  
這篇文章主要介紹了C# Random類的正確應(yīng)用方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

Random類介紹

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

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

  • Random r= new Random()。會以當(dāng)前系統(tǒng)時間作為默認種子構(gòu)建一個隨機序列
  • Random r = new Random(unchecked((int)DateTime.Now.Ticks));。自定義一個種子,通常會使用時間Ticks。

隨機性保證

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

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

運行結(jié)果:

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

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.

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

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

  /// <summary>
  /// 生成一個10位隨機數(shù)
  /// 設(shè)定了一定的復(fù)雜性,保證單線程下隨機數(shù)不重復(fù)
  /// </summary>
  /// <param name="random">Random.</param>
  /// <returns>隨機數(shù).</returns>
  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);
  }
  /// <summary>
  /// 單線程基本可以保證唯一性
  /// </summary>
  public static void Good_Random_In_SingleThread()
  {
    //正確做法應(yīng)當(dāng)將 Random構(gòu)建防止循環(huán)外。
    //Random創(chuàng)建間隔時間極短的情況下,隨機算法序列會基本一致,倒是隨機性也是一致的
    var r = new Random();
    ConcurrentBag<string> list = new ConcurrentBag<string>();
    for (int i = 0; i < 20000; i++)
    {
      var val = GenerateRandomStr(r);
      list.Add(val);
    }

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

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

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

運行結(jié)果:

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

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

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

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

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

運行結(jié)果:

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

那么到這里Random的隨機性問題解決了嗎??

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

那么解決方案也很簡單,保證每臺服務(wù)器的初始seed不同即可。這里的解決方案很多,不限于機器編號、IP地址后幾位、啟動時間(Environment.TickCount)等等。

這樣,到這里Random的隨機性問題終于可以告一段落了。

到此這篇關(guān)于C# Random類的正確應(yīng)用方法的文章就介紹到這了,更多相關(guān)C# Random類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C#調(diào)用sql2000存儲過程方法小結(jié)

    C#調(diào)用sql2000存儲過程方法小結(jié)

    這篇文章主要介紹了C#調(diào)用sql2000存儲過程的方法,以實例形式分別對調(diào)用帶輸入?yún)?shù)及輸出參數(shù)的存儲過程進行了詳細分析,非常具有實用價值,需要的朋友可以參考下
    2014-10-10
  • 如何在datatable中使用groupby進行分組統(tǒng)計

    如何在datatable中使用groupby進行分組統(tǒng)計

    如何在datatable中進行分組,并且計算分組后每組的數(shù)量,考慮了一下,可以使用LINQ來實現(xiàn)datatable分組,需要的朋友可以參考下
    2015-08-08
  • C#.NET字符串比較中忽略符號的方法

    C#.NET字符串比較中忽略符號的方法

    C#.NET字符串比較中忽略符號的方法,需要的朋友可以參考一下
    2013-04-04
  • C#使用Socket進行簡單的通訊的示例代碼

    C#使用Socket進行簡單的通訊的示例代碼

    Socket 類是基于與 Linux、macOS 或 Windows 的本機互操作性提供的托管代碼版本的套接字服務(wù),提供了一系列的接口來支持應(yīng)用層的調(diào)用,下面我們就來學(xué)習(xí)一下如何使用Socket進行簡單的通訊,需要的可以參考下
    2023-12-12
  • 基于Avalonia實現(xiàn)自定義彈窗的示例詳解

    基于Avalonia實現(xiàn)自定義彈窗的示例詳解

    對于使用avalonia的時候某些功能需要到一些提示,比如異常或者成功都需要對用戶進行提示,所以需要單獨實現(xiàn)彈窗功能,并且可以自定義內(nèi)部組件,這一期將手動實現(xiàn)一個簡單的小彈窗,并且很容易自定義,希望大家喜歡
    2023-02-02
  • C#二進制讀寫B(tài)inaryReader、BinaryWriter、BinaryFormatter

    C#二進制讀寫B(tài)inaryReader、BinaryWriter、BinaryFormatter

    這篇文章介紹了C#二進制讀寫B(tài)inaryReader、BinaryWriter、BinaryFormatter的用法,文中通過示例代碼介紹的非常詳細。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • C#實現(xiàn)在底圖上動態(tài)生成文字和圖片

    C#實現(xiàn)在底圖上動態(tài)生成文字和圖片

    這篇文章主要為大家詳細介紹了C#實現(xiàn)在底圖上動態(tài)生成文字和圖片,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • C#實現(xiàn)TreeView節(jié)點拖拽的方法

    C#實現(xiàn)TreeView節(jié)點拖拽的方法

    這篇文章主要介紹了C#實現(xiàn)TreeView節(jié)點拖拽的方法,涉及C#針對TreeView節(jié)點的動態(tài)添加及移除技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-09-09
  • C#中使用Split方法拆分字符串實例

    C#中使用Split方法拆分字符串實例

    這篇文章主要介紹了C#中使用Split方法拆分字符串實例,本文給出了使用一個分隔符和多個分隔符拆分字符串的例子,需要的朋友可以參考下
    2014-08-08
  • C#實現(xiàn)簡單的文件加密與解密方式

    C#實現(xiàn)簡單的文件加密與解密方式

    這篇文章主要介紹了C#實現(xiàn)簡單的文件加密與解密方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01

最新評論