Mat*_*ias 1 random f# thread-safety
我对线程和并发性缺乏经验; 为了解决这个问题,我目前正在努力实现F#中的随机搜索算法.我根据现有C#示例的想法编写了一个围绕System.Random类的包装器 - 但由于我不确定如何开始对这个错误行为进行单元测试,我想听听更有经验的人有什么说法,如果我的代码存在明显的缺陷或改进,可能是由于F#语法或线程误解:
open System
open System.Threading
type Probability() =
static let seedGenerator = new Random()
let localGenerator =
new ThreadLocal<Random>(
fun _ ->
lock seedGenerator (
fun _ ->
let seed = seedGenerator.Next()
new Random(seed)))
member this.Draw() =
localGenerator.Value.NextDouble()
Run Code Online (Sandbox Code Playgroud)
我对此的理解是:ThreadLocal确保对于一个实例,每个线程都接收一个随机的Random实例,其自己的随机种子由一个公共的静态Random提供.这样,即使及时创建了类的多个实例,它们也会收到自己的种子,避免了"重复"随机序列的问题.该锁强制执行没有两个线程将获得相同的种子.
这看起来是否正确?有明显的问题吗?
我认为你的方法非常合理 - 使用ThreadLocal可以安全访问Random并使用主随机数生成器提供种子意味着即使你在相似的时间从多个线程访问它也会得到随机值.它在密码学意义上可能不是随机的,但对于大多数其他应用程序应该没问题.
至于测试,这非常棘手.如果Random休息,它将一直返回0,但这只是经验经验,很难说你需要多长时间不安全地访问它.我可以建议的最好的事情是实现一些简单的随机性测试(一些简单的随机测试在WikiPedia上)并从循环中的多个线程访问你的类型 - 尽管这仍然是非常糟糕的测试,因为它可能不会每次都失败.
除此之外,您不需要使用type来封装此行为.它也可以写成一个函数:
open System
open System.Threading
module Probability =
let Draw =
// Create master seed generator and thread local value
let seedGenerator = new Random()
let localGenerator = new ThreadLocal<Random>(fun _ ->
lock seedGenerator (fun _ ->
let seed = seedGenerator.Next()
new Random(seed)))
// Return function that uses thread local random generator
fun () ->
localGenerator.Value.NextDouble()
Run Code Online (Sandbox Code Playgroud)