r - 如何在“R”中使用“parallel::parSapply”在“FORK”集群上生成随机数?
问题描述
我正在尝试从FORK
集群的子进程中生成随机数。我发现史蒂夫韦斯顿的答案概述了三种方式。但是,该答案主要针对使用parallel::mclapply
. 我感兴趣的是我是否可以使用手动创建的FORK
集群来实现类似的效果,以及下面的方法是否有任何副作用。
问题。
# Ensure the `.Random.seed` exists in the main process.
rnorm(1)
# Print the seed.
print(.Random.seed)
# [1] 10407 -1622412906 1293611072 -102526474 -427981783 -110857513 1641877986
# Generate random numbers on the cluster (the problem).
for(i in 1:2) {
# Feedback for clarity.
cat("Run number:", i, "\n")
# Create the `FORK` cluster.
backend <- parallel::makeCluster(2, "FORK")
# Check the values of `.Random.seed` on the child processes.
print(parallel::clusterEvalQ(backend, { .Random.seed }))
# Generate random numbers.
print(parallel::parSapply(backend, 1:2, function(x) rnorm(1)))
# Stop the cluster.
parallel::stopCluster(backend)
# Feedback for clarity.
cat(rep("-", 30), "\n\n")
}
# Run number: 1
# [1] 10407 -1622412906 1293611072 -102526474 -427981783 -110857513 1641877986
# [1] 10407 -1622412906 1293611072 -102526474 -427981783 -110857513 1641877986
# [1] 0.4935776 0.4935776
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#
# Run number: 2
# [1] 10407 -1622412906 1293611072 -102526474 -427981783 -110857513 1641877986
# [1] 10407 -1622412906 1293611072 -102526474 -427981783 -110857513 1641877986
# [1] 0.4935776 0.4935776
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# ...
如您所见,根据史蒂夫韦斯顿的回答,子进程是使用.Random.seed
主进程中存在的副本创建的。因此,如果没有任何东西使.Random.seed
流向前移动(或者它没有被删除),那么每次我创建一个新集群时,我都会得到相同的数字(例如,-110857513 1641877986
)。
一种方法(也许是幼稚的)。
文档mcparallel
说明如果RNG
存在,它将由子进程复制,否则每个子进程将RNG
根据时钟时间和进程 ID 启动:
如果
mc.set.seed = FALSE
,则子进程具有与当前 R 会话相同的初始随机数生成器 (RNG) 状态。如果已使用 RNG(或 .Random.seed 已从保存的工作区恢复),则子项将在与当前会话相同的点开始绘制随机数。如果尚未使用 RNG,则子节点将在第一次使用 RNG 时根据时间和进程 ID 设置种子:这几乎可以保证提供与当前会话和任何其他子节点不同的随机数流过程。
因此,.Random.seed
从主进程中删除副本并让子进程根据时钟时间和进程 ID 初始化自己的进程是否安全?例如,如下所示:
# ...
# Generate random numbers on the cluster (a potential approach)?
for(i in 1:2) {
# Feedback for clarity.
cat("Run number:", i, "\n")
# Create the `FORK` cluster.
backend <- parallel::makeCluster(2, "FORK")
# Check the inherited values of `.Random.seed` on the child processes.
print(parallel::clusterEvalQ(backend, { .Random.seed }))
# Remove the inherited `.Random.seed`.
parallel::clusterEvalQ(backend, rm(list = ls(all.names = TRUE)))
# Generate random numbers and let each child process create a new `.Random.seed`.
print(parallel::parSapply(backend, 1:2, function(x) rnorm(1)))
# Check the values of `.Random.seed`.
print(parallel::clusterEvalQ(backend, { .Random.seed }))
# Stop the cluster.
parallel::stopCluster(backend)
# Feedback for clarity.
cat(rep("-", 30), "\n\n")
}
# Which results in the following output.
# Run number: 1
# [1] 10407 -1622412906 1293611072 -102526474 -427981783 -110857513 1641877986
# [1] 10407 -1622412906 1293611072 -102526474 -427981783 -110857513 1641877986
# [1] -0.5715241 1.1185240
# [1] 10407 526289805 353889827 1059054224 -1056295096 -865117501 2032268800
# [1] 10407 154241933 -599585698 -497710325 -694601912 -34060352 -398990459
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#
# Run number: 2
# [1] 10407 -1622412906 1293611072 -102526474 -427981783 -110857513 1641877986
# [1] 10407 -1622412906 1293611072 -102526474 -427981783 -110857513 1641877986
# [1] -1.1293323 -0.8339863
# [1] 10407 1114672013 -219668828 1458973439 -2063321272 -775346660 1678610177
# [1] 10407 -1649177715 -1213192943 -1982050350 1287862088 -2081396332 185873261
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
快速提一下——我尝试使用parallel::clusterSetRNGStream
,但运气不佳,因为.Random.seed
它存在于主进程中,它会被复制到子进程中。
解决方案
推荐阅读
- android - Firebase 数据库规则问题(“读取”被拒绝;值被自动删除)
- python-3.x - Python:创建日志记录自定义处理程序并配置现有配置文件以将日志重定向到输出小部件
- python - 仅选择 .csv 文件类型上传到 Flask
- python - python 列表理解中的两个for循环,有2个项目
- javascript - 一旦在javascript中选择了一行,如何取消选择其他行?
- c - c语言的gets函数有问题
- html - sign_in_count 第一次使用 Rails
- r - 将 valueBox 标题链接到不同的 tabPanel
- c# - System.Data.SqlClient.SqlException:“函数或过程 update_Faculty 的参数太多。”
- typescript - 不能对 HTMLInputElement 使用 setSelectionRange 方法