为什么 withr::with_seed 和 R.utils::withSeed 在异步代码中使用时会产生不同的结果?
Why do withr::with_seed and R.utils::withSeed generate different results when used in async code?
我正在尝试使用 R 学习异步编程,以便我可以实现一个需要使用指定种子生成随机数的应用程序(始终 使用指定种子)。为此,我一直在使用 R.utils::withSeed
,但我知道 withr::with_seed
也存在,所以我想我可以检查一下。
我知道随机数生成很棘手,所以我一直在尝试 运行 简单的示例来尝试理解其工作原理。我需要:
- ...使用相同的种子时始终获得相同的随机数
- ...使用相同的种子获得相同的随机数 不管 我是否使用异步框架(所以我应该能够 运行承诺之外的代码并得到相同的答案)
在下面的代码中,我定义了两个函数来生成随机数,将种子设置为 withr::with_seed
或 R.utils::withSeed
。
- 当 运行 超出承诺时,这两个函数给了我相同的答案。
- 当 运行 在 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)
future
软件包将默认 RNG 类型设置为 L'Ecuyer-CMRG,而 R 的默认类型是 Mersenne-Twister。 withr::with_seed
将 RNG 类型重置为 "default"
(即 Mersenne-Twister),除非在 .rng_kind
参数中明确指定。 R.utils::withSeed
,另一方面,默认情况下不对 RNG 种类做任何事情,但可以使用传递给 set.seed
的 ...
参数列表指定 RNG 种类。在您的示例中,可以按如下方式修改 s0_R
以获得承诺内外的相同结果。
s0_R = function(seed = 1, n = 1){
R.utils::withSeed(expr = {
rnorm(n)
}, seed = seed, kind = "default")
}
我正在尝试使用 R 学习异步编程,以便我可以实现一个需要使用指定种子生成随机数的应用程序(始终 使用指定种子)。为此,我一直在使用 R.utils::withSeed
,但我知道 withr::with_seed
也存在,所以我想我可以检查一下。
我知道随机数生成很棘手,所以我一直在尝试 运行 简单的示例来尝试理解其工作原理。我需要:
- ...使用相同的种子时始终获得相同的随机数
- ...使用相同的种子获得相同的随机数 不管 我是否使用异步框架(所以我应该能够 运行承诺之外的代码并得到相同的答案)
在下面的代码中,我定义了两个函数来生成随机数,将种子设置为 withr::with_seed
或 R.utils::withSeed
。
- 当 运行 超出承诺时,这两个函数给了我相同的答案。
- 当 运行 在 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)
future
软件包将默认 RNG 类型设置为 L'Ecuyer-CMRG,而 R 的默认类型是 Mersenne-Twister。 withr::with_seed
将 RNG 类型重置为 "default"
(即 Mersenne-Twister),除非在 .rng_kind
参数中明确指定。 R.utils::withSeed
,另一方面,默认情况下不对 RNG 种类做任何事情,但可以使用传递给 set.seed
的 ...
参数列表指定 RNG 种类。在您的示例中,可以按如下方式修改 s0_R
以获得承诺内外的相同结果。
s0_R = function(seed = 1, n = 1){
R.utils::withSeed(expr = {
rnorm(n)
}, seed = seed, kind = "default")
}