3

我正在尝试使用 R 学习异步编程,以便我可以实现一个需要生成具有指定种子的随机数(始终具有指定种子)的应用程序。我一直在使用R.utils::withSeed它,但我知道它withr::with_seed也存在,所以我想我可以检查一下。

我知道随机数生成很棘手,所以我一直在尝试运行简单的示例来尝试了解事情是如何工作的。我需要:

  • ...使用相同的种子时总是得到相同的随机数
  • ...无论我是否使用异步框架,都可以使用相同的种子获得相同的随机数(因此我应该能够在 Promise 之外运行代码并获得相同的答案)

在下面的代码中,我定义了两个函数来生成随机数,使用withr::with_seed或设置种子R.utils::withSeed

  • 当在 promise 之外运行时,这两个函数给了我相同的答案。
  • 这两个函数在 Promise 中运行时给出不同的答案。
  • withr::with_seed版本在承诺内部或外部给出了相同的答案。
  • R.utils::withSeed版本在承诺内部或外部给出了不同的答案。

然而,答案似乎在多次运行中是一致的。

我的问题是:为什么?这是一个错误R.utils::withSeed,还是我误解了什么?


代码


library(future)
library(promises)

plan(multisession)


s0_R = function(seed = 1, n = 1){
  R.utils::withSeed(expr = {
    rnorm(n)
  }, seed = seed)
}

s0_w = function(seed = 1, n = 1){
  withr::with_seed(
     seed = seed,
     code = {
       rnorm(n)
     })
}


s_R = function(seed = 1, n = 1){
  future_promise(
    {
    Sys.sleep(5)
    s0_R(seed, n)
    }, 
    seed = TRUE
  )
} 

s_w = function(seed = 1, n = 1){
  future_promise(
    {
      Sys.sleep(5)
      s0_w(seed, n)
    }, 
    seed = TRUE
  )
} 

s0_R(123) %>%
  paste(" (R.utils::withSeed)\n") %>%
  cat()
# -0.560475646552213  (R.utils::withSeed)

s0_w(123) %>%
  paste(" (withr::with_seed)\n") %>%
  cat()
# -0.560475646552213  (withr::with_seed)

s_R(123) %...>%
  paste(" (async, R.utils::withSeed)\n") %...>%
  cat()

s_w(123) %...>%
  paste(" (async, withr::with_seed)\n") %...>%
  cat()

# Results occur later...
# -0.968592726552943  (async, R.utils::withSeed)
# -0.560475646552213  (async, withr::with_seed)
4

1 回答 1

2

future软件包将默认的 RNG 类型设置为 L'Ecuyer-CMRG,而 R 的默认值为 Mersenne-Twister。除非在参数中明确指定,否则withr::with_seed将 RNG 类型重置为(即 Mersenne-Twister) 。另一方面,默认情况下不对 RNG 种类做任何事情,但是可以使用传递给 的参数列表来指定 RNG 种类。在您的示例中,可以进行如下修改,以在承诺内外获得相同的结果。"default".rng_kindR.utils::withSeed...set.seeds0_R

s0_R = function(seed = 1, n = 1){
  R.utils::withSeed(expr = {
    rnorm(n)
  }, seed = seed, kind = "default")
}
于 2021-08-22T13:23:45.370 回答