在.NET中,随机数一般是用Random来获取,但是当在多任务的并行化编程时,问题就出现了。因为Random是基于时间作为种子来生成伪随机数的,而如果程序在多核并行时,在同一时间内的多个核中取到的时间是一样的,这样一来,生成的伪随机数就有可能会有一样的。如果业务需求中需要不可重复的随机数,那么这后果将会相当严重,所以必须采取一种新的方式来获取线程安全的伪随机数。下面是摘自《.NET Parallel Extensions》中的一段关于线程安全随机数生成的类,也可参看http://code.msdn.microsoft.com/Samples-for-Parallel-b4b76364/sourcecode?fileId=44488&pathId=1352203765。

 public class ThreadSafeRandom : Random{//This is the seed providerprivate static readonly RNGCryptoServiceProvider _global = new RNGCryptoServiceProvider();//This is the provider of randomness.//There is going to be one instance of Random per thread//because it is  declared as ThreadLocal<Random>private ThreadLocal<Random> _local = new ThreadLocal<Random>(() =>{//This is the valueFactory function//This code will run for each thread to initialize each independent instance of Random.var buffer = new byte[4];//Calls the GetBytes method for RNGCryptoServiceProvider because this class is thread-safe//for this usage._global.GetBytes(buffer);//Return the new thread-local Random instance initialized with the generated seed.return new Random(BitConverter.ToInt32(buffer, 0));});public override int Next(){return _local.Value.Next();}public override int Next(int maxValue){return _local.Value.Next(maxValue);}public override int Next(int minValue, int maxValue){return _local.Value.Next(minValue, maxValue);}public override double NextDouble(){return _local.Value.NextDouble();}public override void NextBytes(byte[] buffer){_local.Value.NextBytes(buffer);}}

这个类ThreadSafeRandom继承自Random,所以可以像Random一样使用。

这里边关键用到了几个技术点:

1、RNGCryptoServiceProvider的加密随机生成器,再用其中的强随机序列的方法GetBytes来实现随机。

2、使用ThreadLocal来懒惰初使化(Lazy-Initialize)随机数的实例。因为ThreadLocal是针对于每一个线程的线程安全类,是线程的本地存储形式。如果同一个线程多次初始化ThreadLocal,那么得到的实例将会是一样的。因为如果一个线程已经初始化了该实例之后( ThreadSafeRandom safeRandom = new ThreadSafeRandom()),该线程后面继续初始化(再次调用 ThreadSafeRandom safeRandom = new ThreadSafeRandom())是不会再初始化一次,而是会返回之前的实例(有点像单件模式)。不过,这也带来了另一个问题,如果就是要在线程中不断产生新的实例时,这种做法就变的不合适了,不悉采用变通或者其他做法。

下面是关于Random和ThreadSafeRandom测试的实例

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace Chapter11_Console
{public class RadomTest{#region Run Functionpublic static void Run(){Console.WriteLine("Started!");var sw = Stopwatch.StartNew();int normalRandomSameCount = randomSerial(generateNormalRadoms);Console.WriteLine("Normal Random Same Count:{0}, Consume Time:{1}", normalRandomSameCount, sw.Elapsed.ToString());sw.Restart();int threadSafeRandomSameCount = randomSerial(generateThreadSafeRadoms);Console.WriteLine("Thread Safe Random Same Count:{0}, Consume Time:{1}", threadSafeRandomSameCount, sw.Elapsed.ToString());Console.WriteLine("Completed!");Console.ReadLine();}private static int randomSerial(Func<int, List<int>> generateRadoms){int randomCount = 100000;Task<List<int>>[] tasks = new Task<List<int>>[2];for (int i = 0; i < tasks.Length; i++){tasks[i] = Task.Factory.StartNew(() =>{return generateRadoms(randomCount);});}Task.WaitAll(tasks);int sameCount = 0;Task finalTask = Task.Factory.StartNew(() =>{for (int i = 0; i < randomCount; i++){if (tasks[0].Result[i] == tasks[1].Result[i]){sameCount++;}}});finalTask.Wait();return sameCount;}private static List<int> generateNormalRadoms(int randomCount){List<int> randoms = new List<int>();for (int i = 0; i < randomCount; i++){Random random = new Random();randoms.Add(random.Next());}return randoms;}private static List<int> generateThreadSafeRadoms(int randomCount){List<int> randoms = new List<int>();for (int i = 0; i < randomCount; i++){ThreadSafeRandom safeRandom = new ThreadSafeRandom();randoms.Add(safeRandom.Next());}return randoms;}#endregion}
}

运行结果如下图

多运行几次会发现,有的时候Normal Random Same Count也有为0的时候,有的时候会很小,有的时候会很大,具体多少是随机性的。

注意:

1、测试时必须是多核的。以上程序是在双核上运行的,如果有四核或更多的核,可以将任务数加大。

2、线程安全虽然确保了随机数的安全性,但是会消耗更多时间。

转载请注明出处http://blog.csdn.net/xxdddail/article/details/16980743

转载于:https://www.cnblogs.com/sparkleDai/p/7605067.html

用线程安全随机数解决Random在多线程中随机性重复的问题相关推荐

  1. 解决DataGridView在多线程中无法显示滚动条的问题

    解决DataGridView在多线程中无法显示滚动条的问题 参考文章: (1)解决DataGridView在多线程中无法显示滚动条的问题 (2)https://www.cnblogs.com/roph ...

  2. 解决C/C++语言中全局变量重复定义的问题

    前言 今天,在整理自己的代码的时候,考虑到我写的代码从一至终都是在一个cpp文件里面.于是,想把自己的代码中的各个模块分离开来,以便更好地阅读和管理. 遇到的问题 我的做法是: 宏定义.结构体定义.函 ...

  3. Python线程安全问题及解决方法

    Python线程安全问题及解决方法 Python多线程是通过threading模块来实现的. 参考: https://mp.csdn.net/postedit/91069618 一.多线程共享全局变量 ...

  4. Java 随机数产生 Random和Math 解决

    ઇଓ 欢迎来阅读子豪的博客(Java语法篇) ☾ ⋆有什么宝贵的意见或建议可以在留言区留言 ღღ欢迎 素质三连 点赞 关注 收藏 ❣ฅ码云仓库:补集王子 (YZH_skr) - Gitee.com 目 ...

  5. java线程占用CPU_在windows下揪出java程序占用cpu很高的线程并完美解决

    我的一个java程序偶尔会出现cpu占用很高的情况 一直不知道什么原因 今天终于抽时间解决了 系统是win2003 jvisualvm 和 jconsole貌似都只能看到总共占用的cpu 看不到每个线 ...

  6. python随机数模块_python 随机数模块 -- random

    一.概述 这个模块实现的伪随机数生成器. 对于整数,从区间选取.对于序列,随机元素. 在实线的,有功能来计算均匀分布,正态分布(高斯) ,对数正态分布,负指数,γ和β分布.对于生成的角度分布,冯·米塞 ...

  7. python线程池并发_python 并发编程多线程之进程池/线程池

    一.验证GIL锁的存在 Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行.虽然 Python 解释器中可以"运行"多个线程,但在任意时刻只有一个线程在解释器中运行 ...

  8. java利己线程_第10章 多线程2_Java程序设计与应用开发_ppt_大学课件预览_高等教育资讯网...

    第十章 多线程 杨 娟 it@126.com Java 程序设计 教学内容 ? 线程的概念 ? 多线程的实现 ? 线程的生命周期 ? 线程的中断 ? 线程的优先级 ? 同步线程 ? 小结 10.1 线 ...

  9. python概率随机抽奖_Python利用带权重随机数解决抽奖和游戏爆装备

    关于带权随机数 为了帮助理解,先来看三类随机问题的对比: 1.已有n条记录,从中选取m条记录,选取出来的记录前后顺序不管. 实现思路:按行遍历所有记录,约隔n/m条取一个数据即可 2.在1类情况下,还 ...

  10. linux系统如何查看是否是线程死锁,多线程中如何使用gdb精确定位死锁问题

    本文转载自微信公众号「程序喵大人」,作者程序喵大人 .转载本文请联系程序喵大人公众号. 在多线程开发过程中很多人应该都会遇到死锁问题,死锁问题也是面试过程中经常被问到的问题,这里介绍在c++中如何使用 ...

最新文章

  1. Linux下将Mysql和Apache加入到系统服务里的方法
  2. hadoop + spark+ hive 集群搭建(apache版本)
  3. Spring Boot 2.x基础教程:Spring Data JPA的多数据源配置
  4. C#学习笔记—了解C#
  5. Navicat Premium 12安装及常用快捷键
  6. mysql修改字段名称_MySQL增删改查的常用语句汇总
  7. 问八股文的公司都是垃圾!?
  8. 挣脱浏览器的束缚(5) - 哭笑不得的IE Bug
  9. MySQL 存储过程 if语句
  10. go使用redis——redigo使用HMSET存储结构体
  11. 大三学生独自破解逆天AI模型:我只是把撩妹的时间,都用来研究机器学习了...
  12. 基础总结篇之八:创建及调用自己的ContentProvider
  13. 编译 easyMule-VeryCD
  14. 微型计算机经历了那几个阶段,微型计算机的发展经历了哪几个阶段,各阶段微处理器的主要特征是什么...
  15. Java8 新特性 (五)Stream API
  16. 冷水机组选型公式与运行参数
  17. QT5.9用自定义字体修改qlabel字体、大小以及颜色
  18. python 猪八戒网接单_python接单平台简单整理
  19. 外边距+内边距+边框详解
  20. 留下岁月的痕迹,不负自己所望

热门文章

  1. anaconda装完没反应
  2. linux和Windows之间共享文件
  3. 用python简单处理图片(3):添加水印
  4. Sklearn的聚类算法以及聚类评价指标
  5. 对于机器学习而言如何翻越测试集
  6. 华为服务器修改登录密码,服务器登录修改密码
  7. oracle闪回scn,Oracle闪回查询及scn_to_timestamp
  8. java 打印数据_Java 中的打印流
  9. pads中如何设置等长_如何给PDF中的文本设置高亮显示
  10. C++ 传递指针给函数