.net F中的线程安全正常随机数生成器#

.net F中的线程安全正常随机数生成器#,.net,random,f#,.net,Random,F#,需要一个从正态(高斯)分布返回样本的随机数生成器,我已经移植到F#部分: 设可变m_w=521288629u 设可变m_z=362436069u 让私有getUint()= m_z>>16) m_w>>16) (穆兹16) m|z random normal()|] 此实现工作正常,但不是线程安全的。考虑到依赖于它的代码广泛使用了线程并行库,我需要使它成为线程安全的 这在我看来并不明显,因为该方法的核心是两个几乎不可或缺的可变成员。有没有其他方法可以在不使用锁的情况下实现线程安全 有没有其他方

需要一个从正态(高斯)分布返回样本的随机数生成器,我已经移植到F#部分:

设可变m_w=521288629u
设可变m_z=362436069u
让私有getUint()=
m_z>>16)
m_w>>16)
(穆兹16)
m|z random normal()|]
此实现工作正常,但不是线程安全的。考虑到依赖于它的代码广泛使用了线程并行库,我需要使它成为线程安全的

这在我看来并不明显,因为该方法的核心是两个几乎不可或缺的可变成员。有没有其他方法可以在不使用锁的情况下实现线程安全


有没有其他方法可以实现仅使用不可变成员的普通伪随机生成器?

使用可变成员,您别无选择,只能使用锁

但是,最好使用传递给随机函数的包含
mw
mz
的不可变函数。它们可以返回随机值的元组和包含更新的随机成员的新记录。更好的是,您可以创建一个用于处理生成随机数据的方法,这样您就不必担心随机记录的传递


另外,从随机函数中调用
setSeed
也是不好的。多个后续调用将返回相同的值。您只需要设置一次种子。

下面是一个使用System.Random的简单线程安全解决方案,如果有帮助:

let random =
  let rand = System.Random()
  let locker = obj()
  fun () -> lock locker rand.Next

最好将所有
muw
/
muz
和相关函数放入一个类中。像这样:

type Random = 
    let setSeed() = ...
    let randomNormal() = ...
在这之后,至少有两种解决方案:使用自己的
Random
对象实例启动每个线程;或者为同样的事情使用
ThreadLocal
类——保证每个线程都有自己的
Random
类实例

编辑:
另外,
MailboxProcessor
with
PostAndReply
方法是在线程之间共享单个生成器的好方法。无需担心同步问题。

不要每次都调用setSeed,这是个好主意,愚蠢的疏忽。我喜欢这个主意。你能详细说明一下计算表达式选项吗(我不熟悉这个概念)?它看起来像:
rnd{let!a=GetNext 10;let!b=GetExponential 2.5;let!c=GetNormal;返回a,b,c}
,定义一个上下文,在该上下文中隐式使用随机数生成器(在
let!
语句中)。
rnd{…}
表达式的类型类似于
YourRandomGenType->'a
每次创建新实例的问题是它们可能会获得相同的种子。我认为这很可能发生在Array.Parallel.map(fun->let r=new Random()…)场景中。@FrancescoDeVittori:您可以在种子值中包含线程特定的数据,比如
thread.CurrentThread.ManagedThreadId
@FrancescoDeVittori是的,使用
DateTime
作为初始种子是个坏主意。但是您可以使用
RNGCryptoServiceProvider.GetBytes
或类似的东西。@Daniel您假设它们不是在同一个线程上创建的,这很可能是很可能的。@jonharop:是的,如果每个线程都有自己的
Random
对象,这是使用唯一种子值初始化它们的一种方法。您实际上可以使用以下方法:。将
System.random
生成的随机数转换为正态分布数。
type Random = 
    let setSeed() = ...
    let randomNormal() = ...