Как создать индикатор выполнения при использовании функции «foreach ()» в R? - PullRequest
39 голосов
/ 24 марта 2011

Есть несколько информативных постов о том, как создать счетчик для циклов в R-программе. Однако как создать аналогичную функцию при использовании распараллеленной версии с функцией «foreach ()»?

Ответы [ 7 ]

37 голосов
/ 23 октября 2014

Редактировать: После обновления в пакете 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) 

Это - это индикатор выполненияпохоже.Это выглядит немного странно, так как новая полоса печатается для каждой последовательности полос и потому, что рабочий может немного отставать, что иногда приводит к тому, что полоса прогресса перемещается взад и вперед.

8 голосов
/ 11 февраля 2016

Теперь это возможно с пакетом 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.

8 голосов
/ 11 июня 2012

Этот код является модифицированной версией примера 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)

Вы должны знать количество итераций и функцию комбинирования заранее.

6 голосов
/ 25 марта 2011

Вы сохраняете время запуска с помощью 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, что означает, что элементы распределяются по процессам один за другим в порядке завершения предыдущих элементов.

1 голос
/ 01 июля 2018

В этом коде реализован индикатор выполнения, отслеживающий параллельный цикл foreach с использованием бэкэнда doMC и использующий превосходный пакет progress в R.Предполагается, что все ядра, указанные в numCores, выполняют примерно одинаковый объем работы.

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)
}
0 голосов
/ 03 января 2019

Вы также можете настроить это для работы с пакетом progress.

what it looks like

# 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) 
0 голосов
/ 30 мая 2011

Следующий код создаст хороший индикатор в 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, но я бы хотел, чтобы кто-то доказал, что я не прав, поскольку это будет очень полезная функция.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...