为什么不在 RStudio 中打印并行作业?

Why don't parallel jobs print in RStudio?

为什么使用 mclapply 并行化的脚本在集群上打印而不是在 RStudio 中打印?只是出于好奇。

mclapply(1:10, function(x) {
  print("Hello!")
  return(TRUE)
}, mc.cores = 2)
# Hello prints in slurm but not RStudio

None '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"

符合预期,但当我尝试时:

bfr <- utils::capture.output({
  y <- parallel::mclapply(1:3, FUN = print)
})
print(bfr)
## character(0)

没有捕获到输出。有趣的是,如果我调用它而不在终端的 Linux 上捕获 R 4.0.1 中的输出,我会得到:

y <- parallel::mclapply(1:3, FUN = print)
[1] 1
[1] 3
[1] 2

很有趣,嗯?

您在使用本地 PSOCK 集群时可能会得到的另一个建议是在创建集群时设置参数 outfile = ""。事实上,当你在终端中的 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

但这也给了错误的希望。事实证明,您 看到 的输出只是因为终端恰好显示了它。这在 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)

有趣吧?但如果你了解 'parallel' 包的内部细节,其实并不奇怪。


(免责声明:我是作者)据我所知,唯一可以正确中继标准输出(例如 cat()print()、...)和消息条件(例如 message()) 到主 R 会话的是 future framework. You can read about the details in its 'Text and Message Output' vignette 但这里有一个例子表明它有效:

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"

无论底层并行化框架如何,它的工作原理都是一样的,例如与本地 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"

这在您 运行 R 所在的所有操作系统和环境中都适用,包括 RStudio 控制台。无论您使用哪种未来的 map-reduce 框架,它的行为都是相同的,例如(此处)future.apply, furrr, and foreach with doFuture.