linux随机数 多线程,用线程安全随机数解决Random在多线程中随机性重复的问题

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

private 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

private ThreadLocal _local = new ThreadLocal(() =>

{

//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 Function

public 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> generateRadoms)

{

int randomCount = 100000;

Task>[] tasks = new Task>[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 generateNormalRadoms(int randomCount)

{

List randoms = new List();

for (int i = 0; i < randomCount; i++)

{

Random random = new Random();

randoms.Add(random.Next());

}

return randoms;

}

private static List generateThreadSafeRadoms(int randomCount)

{

List randoms = new List();

for (int i = 0; i < randomCount; i++)

{

ThreadSafeRandom safeRandom = new ThreadSafeRandom();

randoms.Add(safeRandom.Next());

}

return randoms;

}

#endregion

}

}

运行结果如下图

0818b9ca8b590ca3270a3433284dd417.png

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

注意:

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值