doParallel worker 的输出
output of doParallel workers
假设我有一段代码在 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.
许多解决方案——比如不在 worker 中使用 print
或在那里指定输出文件——浮现在脑海中,但问题明确要求 不更改代码 .因此,我假设当前在 %dopar%
正文中的代码包含在一个无法更改的函数中:
doNotTouch <- function(idx) {
set.seed(idx)
smp <- rnorm(10)
print(sprintf('Index: %d', idx))
cat(sprintf('Value: %f \n', smp[1:10]))
}
一个解决方案是直接指定输出文件 before doNotTouch
被调用(或者更准确地说:在输出被重定向到一个环境中执行函数某个文件):
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()
returns 工人的 PID 可用于写入单独的日志文件 by worker(与 by 相对迭代).
假设我有一段代码在 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.
许多解决方案——比如不在 worker 中使用 print
或在那里指定输出文件——浮现在脑海中,但问题明确要求 不更改代码 .因此,我假设当前在 %dopar%
正文中的代码包含在一个无法更改的函数中:
doNotTouch <- function(idx) {
set.seed(idx)
smp <- rnorm(10)
print(sprintf('Index: %d', idx))
cat(sprintf('Value: %f \n', smp[1:10]))
}
一个解决方案是直接指定输出文件 before doNotTouch
被调用(或者更准确地说:在输出被重定向到一个环境中执行函数某个文件):
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()
returns 工人的 PID 可用于写入单独的日志文件 by worker(与 by 相对迭代).