Dan*_*man 1 parallel-processing r rstudio mclapply
mclapply为什么脚本在集群上可以与打印并行,但在 RStudio 中却不能?只是出于好奇才问。
mclapply(1:10, function(x) {
print("Hello!")
return(TRUE)
}, mc.cores = 2)
# Hello prints in slurm but not RStudio
Run Code Online (Sandbox Code Playgroud)
“parallel”包中的任何函数都不能保证发送到标准输出(stdout)或标准错误(stderr)的输出正确显示在工作程序上。对于所有类型的并行化方法都是如此,例如分叉处理 ( mclapply()) 或 PSOCK 集群 ( parLapply())。其原因是因为它从未被设计为以一致的方式中继输出。
一个好的测试是看看您是否可以通过捕获输出capture.output()。例如,我得到:
bfr <- utils::capture.output({
y <- lapply(1:3, FUN = print)
})
print(bfr)
## [1] "[1] 1" "[1] 2" "[1] 3"
Run Code Online (Sandbox Code Playgroud)
正如预期的那样,但是当我尝试时:
bfr <- utils::capture.output({
y <- parallel::mclapply(1:3, FUN = print)
})
print(bfr)
## character(0)
Run Code Online (Sandbox Code Playgroud)
没有捕获任何输出。但有趣的是,如果我在 Linux 上的终端中调用它而不捕获 R 4.0.1 中的输出,我会得到:
y <- parallel::mclapply(1:3, FUN = print)
[1] 1
[1] 3
[1] 2
Run Code Online (Sandbox Code Playgroud)
有趣,嗯?
outfile = ""使用本地 PSOCK 集群时可能会得到的另一个建议是在创建集群时设置参数。事实上,当您在 Linux 终端上尝试此操作时,它看起来确实有效:
cl <- parallel::makeCluster(2L, outfile = "")
## starting worker pid=25259 on localhost:11167 at 17:50:03.974
## starting worker pid=25258 on localhost:11167 at 17:50:03.974
y <- parallel::parLapply(cl, 1:3, fun = print)
## [1] 1
## [1] 2
## [1] 3
Run Code Online (Sandbox Code Playgroud)
但这也带来了虚假的希望。事实证明,您看到的输出只是因为终端恰好显示了它。这在 RStudio 控制台中可能有效,也可能无效。您可能会在 Linux、macOS 和 MS Windows 上看到不同的行为。理解中最重要的部分是您的 R 会话根本看不到此输出。如果我们尝试捕获它,我们会得到:
bfr <- utils::capture.output({
y <- parallel::parLapply(cl, 1:3, fun = print)
})
## [1] 1
## [1] 2
## [1] 3
print(bfr)
## character(0)
Run Code Online (Sandbox Code Playgroud)
有趣,嗯?但如果您了解“并行”包的内部细节,实际上并不奇怪。
(免责声明:我是作者)据我所知,唯一能够将标准输出(例如cat(),,print()...)和消息条件(例如message(),)正确中继到主 R 会话的并行框架是未来框架。您可以在其“文本和消息输出”小插图中阅读详细信息,但这里有一个示例显示它的工作原理:
future::plan("multicore", workers = 2) ## forked processing
bfr <- utils::capture.output({
y <- future.apply::future_lapply(1:3, FUN = print)
})
print(bfr)
[1] "[1] 1" "[1] 2" "[1] 3"
Run Code Online (Sandbox Code Playgroud)
无论底层并行化框架如何,它的工作原理都是相同的,例如使用本地 PSOCK 工作程序:
future::plan("multisession", workers = 2) ## PSOCK cluster
bfr <- utils::capture.output({
y <- future.apply::future_lapply(1:3, FUN = print)
})
print(bfr)
[1] "[1] 1" "[1] 2" "[1] 3"
Run Code Online (Sandbox Code Playgroud)
这在运行 R 的所有操作系统和环境(包括 RStudio 控制台)上都是相同的。无论您使用哪个未来的映射缩减框架,它的行为都是相同的,例如(此处)future.apply、furrr和foreach与doFuture。