doParallel workers

时间:2015-09-01 14:55:46

标签: r parallel-processing

假设我有一个代码在 foreach 循环中执行各种计算,为简单起见,请将其作为:

foreach( idx = 1:10 ) %dopar% {
   set.seed(idx)
   smp <- rnorm(10)
   print( sprintf('Index: %d', idx) )
   print( cat(sprintf('Value: %f \n', smp[1:10])) )
}

代码的主要思想是它的输出以这样的方式写入,索引被呈现一次,之后是主代码的各种结果。使用%do%时,可以很容易地读取日志文件并使用此类结构进行调试,但是对于%dopar%,日志文件会变得混乱。

问题:如果不更改代码,每个工作人员是否有办法创建自己的输出文件?我是使用doParallel的新手,所以我到目前为止找到的并行输出的唯一方法是使用以下内容:

library(doParallel)
cl <- makeCluster(4, outfile = 'log.txt')
registerDoParallel(cl)

但是,outfile只接受一个字符串作为参数,但没有找到一种向其传递名称向量的方法。那么,也许有办法为每个工人指定一个输出文件?

注意:在Windows 7上工作。

1 个答案:

答案 0 :(得分:1)

许多解决方案 - 比如在工作程序中不使用print或在那里指定输出文件 - 会浮现在脑海中,但问题明确要求不更改代码。因此,我假设当前在%dopar%正文中的代码包含在一个无法更改的函数中:

doNotTouch <- function(idx) {
  set.seed(idx)
  smp <- rnorm(10)
  print(sprintf('Index: %d', idx))
  cat(sprintf('Value: %f \n', smp[1:10]))
}

一种解决方案是在调用 doNotTouch之前直接指定输出文件(或者更准确地说:在将输出重定向到某个文件的环境中执行该函数): / p>

library(doParallel)
cl <- makeCluster(4)
registerDoParallel(cl)


foreach(idx = 1:10) %dopar% {
  capture.output(
    doNotTouch(idx), 
    file = paste0("log", idx, ".txt"))
}

stopCluster(cl)

这不会更改问题中提供的代码,而是将其放在一个处理正确输出文件log_[idx].txt的包装器中。

编辑:在评论中,有人澄清说,问题不在于写入单独的文件,而在于获取不混乱的输出。在这种情况下,可以在循环中使用return(capture.output(doNotTouch(idx)))来收集属于一起的输出并立即返回它们。此外,@ Nutle发现Sys.getpid()返回一个工人的PID,可以用来编写单独的日志文件 by worker (通过迭代选择)。