Как создать индикатор выполнения при использовании функции "foreach()" в R?
есть некоторые информационные сообщения о том, как создать счетчик для циклов в программе R. Однако как вы создаете аналогичную функцию при использовании параллельной версии с "foreach()"?
Ответы
Ответ 1
Изменить: после update в пакет doSNOW стало довольно просто отображать хороший индикатор выполнения при использовании %dopar%
, и он работает на Linux, Windows и OS X
doSNOW
теперь официально поддерживает индикаторы выполнения через аргумент .options.snow
.
library(doSNOW)
cl <- makeCluster(2)
registerDoSNOW(cl)
iterations <- 100
pb <- txtProgressBar(max = iterations, style = 3)
progress <- function(n) setTxtProgressBar(pb, n)
opts <- list(progress = progress)
result <- foreach(i = 1:iterations, .combine = rbind,
.options.snow = opts) %dopar%
{
s <- summary(rnorm(1e6))[3]
return(s)
}
close(pb)
stopCluster(cl)
Еще один способ отслеживания прогресса, если вы помните об общем количестве итераций, заключается в установке .verbose = T
, поскольку это будет печатать на консоли, итерации которой завершены.
Предыдущее решение для Linux и OS X
В Ubuntu 14.04 (64 бит) и OS X (El Capitan) индикатор выполнения отображается даже при использовании %dopar%
, если в makeCluster
функция oufile = ""
установлена. Кажется, он не работает под Windows. С помощью makeCluster
:
outfile: где направлять выходные сообщения stdout и stderr от рабочих. "" указывает на отсутствие перенаправления (что может быть полезно только для рабочих на локальной машине). По умолчанию используется '/dev/null (' nul: в Windows).
Пример кода:
library(foreach)
library(doSNOW)
cl <- makeCluster(4, outfile="") # number of cores. Notice 'outfile'
registerDoSNOW(cl)
iterations <- 100
pb <- txtProgressBar(min = 1, max = iterations, style = 3)
result <- foreach(i = 1:iterations, .combine = rbind) %dopar%
{
s <- summary(rnorm(1e6))[3]
setTxtProgressBar(pb, i)
return(s)
}
close(pb)
stopCluster(cl)
Это, как выглядит индикатор выполнения. Это выглядит немного странно, так как новый штрих печатается для каждой прогрессии бара и потому, что работник может немного отстать, что заставляет индикатор прогресса периодически возвращаться взад и вперед.
Ответ 2
Этот код является модифицированной версией примера doRedis и будет создавать индикатор выполнения даже при использовании %dopar%
с параллельным бэкэнд:
#Load Libraries
library(foreach)
library(utils)
library(iterators)
library(doParallel)
library(snow)
#Choose number of iterations
n <- 1000
#Progress combine function
f <- function(){
pb <- txtProgressBar(min=1, max=n-1,style=3)
count <- 0
function(...) {
count <<- count + length(list(...)) - 1
setTxtProgressBar(pb,count)
Sys.sleep(0.01)
flush.console()
c(...)
}
}
#Start a cluster
cl <- makeCluster(4, type='SOCK')
registerDoParallel(cl)
# Run the loop in parallel
k <- foreach(i = icount(n), .final=sum, .combine=f()) %dopar% {
log2(i)
}
head(k)
#Stop the cluster
stopCluster(cl)
Вы должны знать количество итераций и функцию комбинации загодя.
Ответ 3
Теперь это возможно с пакетом parallel
. Протестировано с помощью R 3.2.3 на OSX 10.11, работающим внутри RStudio, с использованием кластера "PSOCK"
.
library(doParallel)
# default cluster type on my machine is "PSOCK", YMMV with other types
cl <- parallel::makeCluster(4, outfile = "")
registerDoParallel(cl)
n <- 10000
pb <- txtProgressBar(0, n, style = 2)
invisible(foreach(i = icount(n)) %dopar% {
setTxtProgressBar(pb, i)
})
stopCluster(cl)
Странно, он отображается только с помощью style = 3
.
Ответ 4
Вы сохраняете время начала с Sys.time()
до цикла. Перебирайте строки или столбцы или что-то общее. Затем внутри цикла вы можете вычислить время, прошедшее до сих пор (см. difftime
), процент завершения, скорость и расчетное время. Каждый процесс может печатать эти строки прогресса с помощью функции message
. Вы получите что-то вроде
1/1000 complete @ 1 items/s, ETA: 00:00:45
2/1000 complete @ 1 items/s, ETA: 00:00:44
Очевидно, что порядок циклов сильно повлияет на то, насколько хорошо это работает. Не знаю о foreach
, но с multicore
mclapply
вы получите хорошие результаты, используя mc.preschedule=FALSE
, что означает, что элементы распределяются на процессы поочередно, так как предыдущие элементы завершаются.
Ответ 5
Следующий код создаст хороший индикатор выполнения в R для структуры управления foreach. Он также будет работать с графическими индикаторами выполнения, заменив txtProgressBar на желаемый объект строки выполнения.
# Gives us the foreach control structure.
library(foreach)
# Gives us the progress bar object.
library(utils)
# Some number of iterations to process.
n <- 10000
# Create the progress bar.
pb <- txtProgressBar(min = 1, max = n, style=3)
# The foreach loop we are monitoring. This foreach loop will log2 all
# the values from 1 to n and then sum the result.
k <- foreach(i = icount(n), .final=sum, .combine=c) %do% {
setTxtProgressBar(pb, i)
log2(i)
}
# Close the progress bar.
close(pb)
В то время как приведенный выше код отвечает на ваш вопрос в его самой базовой форме, более сложный и более сложный вопрос: можете ли вы создать индикатор выполнения R, который контролирует ход выполнения инструкции foreach, когда она распараллеливается с% dopar%. К сожалению, я не думаю, что можно контролировать прогресс параллельного foreach таким образом, но я бы хотел, чтобы кто-то доказал мне свою ошибку, поскольку это будет очень полезная функция.