il y a quelques messages informatifs sur la création d'un compteur de boucles dans un programme R. Cependant, comment créez-vous une fonction similaire lorsque vous utilisez la version parallélisée avec "foreach ()"?
Edit: Après un update vers le paquet doSNOW, il est devenu très simple d’afficher une barre de progression de Nice lorsqu’on utilise %dopar%
et cela fonctionne sous Linux, Windows et OS X
doSNOW
supporte maintenant officiellement les barres de progression via l'argument .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)
Un autre moyen de suivre les progrès, si vous gardez à l'esprit le nombre total d'itérations, consiste à définir .verbose = T
, car cela affichera sur la console les itérations terminées.
Solution précédente pour Linux et OS X
Sous Ubuntu 14.04 (64 bits) et OS X (El Capitan), la barre de progression est affichée même si vous utilisez %dopar%
si la fonction makeCluster
oufile = ""
est définie. Cela ne semble pas fonctionner sous Windows. De l'aide sur makeCluster
:
outfile: Où diriger les sorties stdout et stderr de la sortie des travailleurs. "" n'indique aucune redirection (elle ne peut être utile que pour les travailleurs de la machine locale). La valeur par défaut est '/ dev/null' ('nul:' sous Windows).
Exemple de code:
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)
Ceci est ce à quoi la barre de progression ressemble. Cela semble un peu étrange, car une nouvelle barre est imprimée pour chaque progression de la barre et parce qu'un travailleur risque de perdre un peu de temps, ce qui entraîne un basculement occasionnel de la barre de progression.
Ce code est une version modifiée de l’exemple doRedis , et créera une barre de progression même lors de l’utilisation de %dopar%
avec un serveur parallèle:
#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)
Vous devez connaître le nombre d'itérations et la fonction de combinaison à l'avance.
Ceci est maintenant possible avec le package parallel
. Testé avec R 3.2.3 sur OSX 10.11, s’exécutant dans RStudio, à l’aide d’un cluster de type "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)
Étrangement, il ne s'affiche correctement qu'avec style = 3
.
Vous enregistrez l'heure de début avec Sys.time()
avant la boucle. Boucle sur des lignes ou des colonnes ou quelque chose dont vous connaissez le total. Ensuite, à l’intérieur de la boucle, vous pouvez calculer le temps écoulé jusqu’à présent (voir difftime
), le pourcentage d’achèvement, la vitesse et le temps estimé qui reste. Chaque processus peut imprimer ces lignes de progression avec la fonction message
. Vous obtiendrez une sortie quelque chose comme
1/1000 complete @ 1 items/s, ETA: 00:00:45
2/1000 complete @ 1 items/s, ETA: 00:00:44
De toute évidence, l'ordre de bouclage affectera grandement l'efficacité de ce processus. Je ne connais pas foreach
, mais avec multicore
's mclapply
, vous obtiendrez de bons résultats en utilisant mc.preschedule=FALSE
, ce qui signifie que les éléments sont affectés aux processus un par un dans l'ordre d'achèvement des éléments précédents.
Ce code implémente une barre de progression effectuant le suivi d'une boucle foreach
parallélisée à l'aide du backend doMC
et de l'excellent progress package dans R
. Il suppose que tous les cœurs, spécifiés par numCores
, effectuent une quantité de travail à peu près égale.
library(foreach)
library(doMC)
library(progress)
iterations <- 100
numCores <- 8
registerDoMC(cores=numCores)
pbTracker <- function(pb,i,numCores) {
if (i %% numCores == 0) {
pb$tick()
}
}
pb <- progress_bar$new(
format <- " progress [:bar] :percent eta: :eta",
total <- iterations / numCores, clear = FALSE, width= 60)
output = foreach(i=1:iterations) %dopar% {
pbTracker(pb,i,numCores)
Sys.sleep(1/20)
}
Vous pouvez également obtenir que cela fonctionne avec le paquetage progress
.
# loading parallel and doSNOW package and creating cluster ----------------
library(parallel)
library(doSNOW)
numCores<-detectCores()
cl <- makeCluster(numCores)
registerDoSNOW(cl)
# progress bar ------------------------------------------------------------
library(progress)
iterations <- 100 # used for the foreach loop
pb <- progress_bar$new(
format = "letter = :letter [:bar] :elapsed | eta: :eta",
total = iterations, # 100
width = 60)
progress_letter <- rep(LETTERS[1:10], 10) # token reported in progress bar
# allowing progress bar to be used in foreach -----------------------------
progress <- function(n){
pb$tick(tokens = list(letter = progress_letter[n]))
}
opts <- list(progress = progress)
# foreach loop ------------------------------------------------------------
library(foreach)
foreach(i = 1:iterations, .combine = rbind, .options.snow = opts) %dopar% {
summary(rnorm(1e6))[3]
}
stopCluster(cl)