[英]Thread-safe normal random number generator in F#
需要一個從普通(高斯)分布返回樣本的隨機數生成器,我已經移植到F#作為John D. Cook的C#生成器的一部分 :
let mutable m_w = 521288629u
let mutable m_z = 362436069u
let private getUint () =
m_z <- 36969u * (m_z &&& 65535u) + (m_z >>> 16)
m_w <- 18000u * (m_w &&& 65535u) + (m_w >>> 16)
(m_z <<< 16) + m_w
let private setSeed () =
let dt = System.DateTime.Now
let x = dt.ToFileTime ()
m_w <- uint32 (x >>> 16)
m_z <- uint32 (x % 4294967296L)
let private getUniform () =
let u = getUint ()
(float u + 1.) * 2.328306435454494e-10
let private randomNormal () =
let u1 = getUniform ()
let u2 = getUniform ()
let r = sqrt (-2. * (log u1))
let theta = 2. * System.Math.PI * u2
r * sin (theta)
/// Returns a normal (Gaussian) random sample with mean 0 and standard deviation 1
let randn () =
setSeed ()
randomNormal ()
/// Returns an array of normal (Gaussian) random samples
let randns n m =
setSeed ()
[| for i in 0 .. n - 1 -> randomNormal () |]
此實現工作正常但不是線程安全的。 鑒於依賴於它的代碼廣泛使用了Thread Parallel Library,我需要使它成為線程安全的。
這對我來說並不明顯,因為該方法的核心是兩個可變成員,這幾乎是不可或缺的。 有沒有其他方法來實現線程安全而不訴諸鎖定?
有沒有其他方法來實現僅使用不可變成員的普通偽隨機生成器?
這是一個使用System.Random的簡單線程安全解決方案,如果它有任何幫助:
let random =
let rand = System.Random()
let locker = obj()
fun () -> lock locker rand.Next
最好將所有m_w
/ m_z
和相關函數放入一個類中。 像這樣:
type Random =
let setSeed() = ...
let randomNormal() = ...
之后至少有兩個解決方案:使用自己的Random
對象實例啟動每個線程; 或者使用ThreadLocal<Random>
類ThreadLocal<Random>
同樣的事情 - 保證每個線程都有自己的Random
類實例。
編輯:另外,使用PostAndReply
方法的MailboxProcessor
是在線程之間共享單個生成器的好方法。 無需擔心同步。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.