【问题标题】:Is the random number generator in Haskell thread-safe?Haskell 中的随机数生成器是线程安全的吗?
【发布时间】:2011-08-22 20:32:12
【问题描述】:

是所有线程都共享同一个“全局随机数生成器”,还是每个线程都有自己的?

如果是共享的,如何确保线程安全? "Monads" chapter of Real World Haskell 中描述的使用 getStdGensetStdGen 的方法看起来并不安全。

如果每个线程都有一个独立的生成器,那么快速连续启动的两个线程的生成器是否会有不同的种子? (例如,如果种子是以秒为单位的时间,他们不会,但毫秒可能没​​问题。我不知道如何从 Data.Time 获得毫秒分辨率的时间。)

【问题讨论】:

    标签: multithreading random thread-safety haskell


    【解决方案1】:

    有一个名为newStdGen 的函数,它提供了一个新的标准。 gen 每次被调用。 Its implementation 使用 atomicModifyIORef,因此是线程安全的。

    newStdGen 不仅在线程安全方面比 get/setStdGen 更好,而且还可以保护您免受像这样的潜在单线程错误:let rnd = (fst . randomR (1,5)) <$> getStdGen in (==) <$> rnd <*> rnd

    此外,如果您考虑 newStdGengetStdGen/setStdGen 的语义,第一个可能非常简单:您只需获得一个新的 std。 gen 处于随机状态,非确定性地选择。另一方面,使用 get/set 对,您无法抽象出全局程序状态,这有多种原因是不好的。

    【讨论】:

    【解决方案2】:

    我建议您只使用一次getStdGen(在主线程中),然后使用split 函数生成新的生成器。我会这样做:

    创建一个包含生成器的MVar。每当一个线程需要一个新的生成器时,它就会从MVar 中取出当前值,调用split 并将新的生成器放回去。由于MVar 的功能,这应该是线程安全的。

    【讨论】:

    • 事实上,Rotsor's answer 中描述的newStdGen 操作正是这样做的;它的文档指出“[it] [a] 将split 应用于当前的全局随机生成器,用其中一个结果更新它,然后返回另一个”,它的实现就是atomicModifyIORef theStdGen split
    • 哇。不知道有这样的功能。
    【解决方案3】:

    就其本身而言,getStdGensetStdGen 在某种意义上不是线程安全的。假设两个线程都执行这个动作:

    do ...
       g <- getStdGen
       (v, g') <- someRandOperation g
       setStdGen g'
    

    线程有可能在另一个线程到达setStdGen 之前都运行g &lt;- getStdGen 行,因此它们都可以获得完全相同的生成器。 (我错了吗?)

    如果它们都抓取相同版本的生成器,并在相同的函数中使用它,它们将得到相同的“随机”结果。因此,在处理随机数生成和多线程时,您确实需要更加小心。有很多解决方案;想到的一个是有一个专用的随机数生成器线程,它产生一个随机数流,其他线程可以以线程安全的方式使用这些随机数。正如 FUZxxl 所建议的,将生成器放在 MVar 中可能是最简单、最直接的解决方案。

    当然,我鼓励您检查您的代码并确保有必要在多个线程中生成随机数。

    【讨论】:

      【解决方案4】:

      您可以在 FUZxxl 的回答中使用 split。但是,当您调用forkIO 时,不要使用 MVar,只需让分叉线程的 IO 操作关闭其中一个生成的生成器,而将另一个留给原始线程。这样每个线程都有自己的生成器。

      正如 Dan Burton 所说,请检查您的代码,看看您是否真的需要多线程中的 RNG。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-07
        • 1970-01-01
        • 1970-01-01
        • 2020-01-31
        • 1970-01-01
        • 2017-04-20
        • 2010-11-11
        相关资源
        最近更新 更多