使用%dopar%时如何打印


69

我有一个foreach循环,使用%dopar%doSNOW作为后端。如何让循环在每次迭代中打印出一些内容?

我下面的代码是我当前正在使用的代码,但未打印任何内容。

foreach(ntree=rep(25,2),.combine=combine,.packages='randomForest',
    .inorder=FALSE) %dopar% {
        print("RANDOM FOREST")
        randomForest(classForm,data=data,na.action=na.action,do.trace=do.trace,ntree=ntree,mtry=mtry)
    }   

2
啊,但是它正在打印,只是不在主节点上...
Joshua Ulrich

1
哦好的。在那种情况下,我可以查看其打印内容或将其打印到主节点上吗?
peopleHuman2012年

我一无所知,我不确定该怎么做。
Joshua Ulrich 2012年

可以编写一个打印到控制台的迭代器函数吗?迭代器应该由主服务器运行,不是吗?
诺姆·罗斯

@NoamRoss是的,迭代器仅在主服务器上运行,因此它可以写入控制台。这将使您可以监视发送给工作人员的任务,而不是监视工作人员实际执行任务的时间。
史蒂夫·韦斯顿

Answers:


26

这里发布了许多好的解决方案,但是我发现最简单的方法是登录到套接字并使用单独的过程在控制台中输出日志调用。

我使用以下功能:

log.socket <- make.socket(port=4000)

Log <- function(text, ...) {
  msg <- sprintf(paste0(as.character(Sys.time()), ": ", text, "\n"), ...)
  cat(msg)
  write.socket(log.socket, msg)
}

然后,您可以将日志语句放置在代码中,例如:

Log("Processing block %d of %d", i, n.blocks)

可以使用任何简单的套接字侦听工具实时查看日志输出。例如,在Linux上使用netcat:

nc -l 4000

上面的日志语句将在netcat终端中显示为:

2014-06-25 12:30:45: Processing block 2 of 13

此方法的优点是可以远程工作,并在您需要记录时提供详细的输出。

ps对于Windows上的用户,请参阅Jon Craton的netcat端口

pps我猜write.socketR函数可能不是线程安全的,但是除非您以高频率登录,否则您不太可能遇到任何问题。有一点要注意。


3
需要运行nc -l 4000在Linux终端之前执行log.sock = make.socket(port=4000)R
horaceT

好的,但是当您有10个不同的过程时,如何正确记录它们?为每个R进程建立一个nc服务器和R套接字?或者只是将R套接字以不同的进程连接到同一台nc服务器?
cloudcomputes

59

缺省情况下,将清除掉雪人产生的输出,但是您可以使用makeCluster的“ outfile”选项进行更改。将outfile设置为空字符串(“”)将防止雪重定向输出,这通常会导致打印消息的输出显示在主进程的终端上。

只需使用以下命令创建并注册集群:

library(doSNOW)
cl <- makeCluster(4, outfile="")
registerDoSNOW(cl)

您的foreach循环根本不需要更改。

对于使用开放式MPI构建的Rmpi的SOCK群集和MPI群集,这都对我有效。在Windows上,如果使用Rgui,则不会看到任何输出。如果改用Rterm.exe,则可以。

请注意,除了您自己的输出之外,您还将看到snow产生的消息,这也可能有用。


要使用进度条,doSNOW版本1.0.14有一个progress选项。这是一个完整的示例:

library(doSNOW)
library(tcltk)
library(randomForest)
cl <- makeSOCKcluster(3)
registerDoSNOW(cl)

ntasks <- 100
pb <- tkProgressBar(max=ntasks)
progress <- function(n) setTkProgressBar(pb, n)
opts <- list(progress=progress)

x <- matrix(runif(500), 100)
y <- gl(2, 50)

rf <- foreach(ntree=rep(25, ntasks), .combine=combine,
        .multicombine=TRUE, .packages='randomForest',
        .options.snow=opts) %dopar% {
  randomForest(x, y, ntree=ntree)
}

progress选项相当笼统,因此您可以使用以下功能简单地打印消息:

progress <- function(n) cat(sprintf("task %d is complete\n", n))

该函数可以接受0、1或2个参数。提供的第一个参数是已完成任务的总数,第二个是刚刚完成的任务的任务号。

最简单的示例仅.在任务完成时打印一个:

progress <- function() cat('.')

此示例同时显示了两个参数,可用于演示任务并非总是按顺序完成:

progress <- function(nfin, tag) {
  cat(sprintf('tasks completed: %d; tag: %d\n', nfin, tag))
}

是否有用于将打印消息的输出定向到控制台的等效解决方案doMC
马特SM

@MattSM使用doMC时,使用标准R时默认情况下会在控制台上显示工作程序的输出。使用RStudio时可能会遇到问题,但由于分叉问题,我不建议在使用RStudio时建议使用doMC。另外,由于并行软件包中的限制,doMC不支持进度条。
史蒂夫·韦斯顿

@SteveWeston我喜欢进度条解决方案。但是有时候我想在每次迭代中查看结果片段。有什么办法做cat(“ it iter i”的结果)吗?
horaceT '18

@horaceT如果您正在使用并行后端,该后端动态地调用了Combine函数(例如doSNOW或doMPI),那么您可以轻松地显示来自Combine函数的结果片段。但是请记住,除非您降低的值,否则仅对第100个结果调用一次Combine函数.maxcombine
史蒂夫·韦斯顿

@SteveWeston第一次发生在我身上:当我使用google时.options.snow,除了您的这个SO线程外,我绝对看不到任何文档。你能解释一下幕后发生的事情吗?在哪里progress得到n的呢?
horaceT

12

我长时间操作过程中保持轨道上的节点进度的方法是创建一个使用一个进度条,tkProgressBartcltk包。它不是您所要求的,但是它应该让您从节点中看到一些东西。至少当群集是在本地主机(这是Windows计算机)上运行的套接字群集时,它才这样做。潜在的问题是进度条要么保留并且使您的监视器混乱,要么进度条变得closed并且打印的信息消失了。对于我来说,这不是问题,因为我只是想知道当前的状态。

library(parallel)
library(doSNOW)
cl<-makeCluster(detectCores(),type="SOCK")
registerDoSNOW(cl)

使用您的代码,

foreach(ntree=rep(25,2),.combine=combine,.packages=c('randomForest','tcltk'),
    .inorder=FALSE) %dopar% {
        mypb <- tkProgressBar(title = "R progress bar", label = "",
          min = 0, max = 1, initial = 0, width = 300)
        setTkProgressBar(mypb, 1, title = "RANDOM FOREST", label = NULL)
    ans <- randomForest(classForm,data=data,na.action=na.action,do.trace=do.trace,ntree=ntree,mtry=mtry)
    close(mypb)
    ans
    }

这是一个更一般的使用示例:

jSeq <- seq_len(30)

foreach(i = seq_len(2), .packages = c('tcltk', 'foreach')) %dopar% {
    mypb <- tkProgressBar(title = "R progress bar", label = "",
        min = 0, max = max(jSeq), initial = 0, width = 300)
    foreach(j = jSeq) %do% {
        Sys.sleep(.1)
        setTkProgressBar(mypb, j, title = "RANDOM FOREST", label = NULL)
    }
    NULL
}

嗨,我尝试使用进度条,但无法使用并行for循环使其工作。每次运行它,我都会收到“ XIO:致命的IO错误”。您如何解决这个问题?@BenBarnes
user88595 2014年

@TAllieri,请参阅更新后的示例(原始示例不是很好的说明)。如果您仍然遇到问题,请提供更多信息并考虑提出新问题。
BenBarnes 2014年

11

我也有同样的问题。我正在使用foreach软件包调整随机森林的参数,并希望在每次迭代后打印“结果”行,但是如果不通过显示进度条之类就无法弄清楚。

这就是我所做的,在我的函数中,我添加了这一行

write.table(result, file=paste("RF_ntree_",ntree,"_dims_",dims,".txt", sep=""),
  sep="\t", row.names=F)

因此,每次迭代之后,结果都会写入一个名称为RF_ntree_250_dims_100.txt之类的文本文件中。

因此,如果要跟踪进度,只需刷新要写入文本文件的文件夹。

PS:结果也在一个数据帧中累积。


2

cat("blah-blah-blah\n", file=stdout())倾向于为我工作(linux / emacs / ess)。我猜它也可以在其他平台上使用。


奇怪的是,如果您在outfile上指定了,则会记录此日志makeCluster。这让我想知道什么是印刷品与此不同。
Sid

我没有在rstudio控制台中看到任何打印输出,它可能会打印到makeCluster中设置的输出文件中,尽管
cloudcomputes

0

一种替代方法是使用文件日志记录(例如,log4r程序包)并在屏幕上单独打印输出(例如,通过“ tail -f”)。

如果您仍然考虑创建日志,则此方法效果很好,并且可以将现有包与所有相关的钟声一起使用。


知道对性能有何影响?即。文件IO中的额外处理时间。
horaceT

否。但是您可以对其进行测试。我仅将此用于相对较慢的任务。
Ott Toomet
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.