Можно ли получить индикатор выполнения с foreach и "многоядерный" бэкэнд

При использовании "многоядерного" параллелизма с использованием foreach и бэкэнда doMC (я использую doMC, поскольку в то время, когда я смотрел на него, другой пакет не позволял вести журнал из я хотел бы получить индикатор выполнения, используя пакет прогресса, но любой прогресс ( который работает на терминале linux, т.е. нет всплывающих окон tcltk).

Учитывая, что он использует forking, я могу себе представить, что это будет невозможно, но я не уверен.

Предполагаемое использование заключается в том, чтобы указать прогресс, когда я загружаю параллельное соединение 100 файлов параллельно (обычно в #! Rscript)

Я просмотрел несколько сообщений, например: Как создать индикатор выполнения при использовании функции "foreach()" в R? , Рад наградить щедрость на этом.

РЕДАКТИРОВАТЬ

500 баллов за подачу за кого-то, показывающего мне, как

  1. используя foreach и многоядерный (разветвляющий) тип параллелизма
  2. получить индикатор выполнения
  3. получить журнал с помощью futile.logger

Reprex

# load packages                                                                                                        
library("futile.logger")                                                                                               
library("data.table")                                                                                                  
library("foreach")                                                                                                     
# create temp dir                                                                                                      
tmp_dir <- tempdir()                                                                                                   
# create names for 200 files to be created                                                                             
nb_files <- 200L                                                                                                       
file_names <- file.path(tmp_dir, sprintf("file_%s.txt", 1:nb_files))                                                   
# make it reproducible                                                                                                 
set.seed(1L)                                                                                                           
nb_rows <- 1000L                                                                                                       
nb_columns <- 10L                                                                                                      
# create those 200 files sequentially                                                                                  
foreach(file_i = file_names) %do%                                                                                      
{                                                                                                                      
    DT <- as.data.table(matrix(data = runif(n = nb_rows * nb_columns), nrow = nb_rows))                                
    fwrite(x = DT, file = file_i)                                                                                      
    flog.info("Creating file %s", file_i)                                                                              
} -> tmp                                                                                                               

# Load back the files                                                                                                  
foreach(file_i = file_names, .final = rbindlist) %dopar%                                                               
{                                                                                                                      
    flog.info("Loading file %s", file_i)                                                                               
    # >>> SOME PROGRESS BAR HERE <<<                                                                                   
    fread(file_i)                                                                                                      
} -> final_data                                                                                                        
# show data                                                                                                            
final_data                                                                                                             

Желаемый выход

Обратите внимание, что индикатор выполнения не перепутан с линиями печати)

INFO [2018-07-18 19:03:48] Loading file /tmp/RtmpB13Tko/file_197.txt
INFO [2018-07-18 19:03:48] Loading file /tmp/RtmpB13Tko/file_198.txt
INFO [2018-07-18 19:03:48] Loading file /tmp/RtmpB13Tko/file_199.txt
INFO [2018-07-18 19:03:48] Loading file /tmp/RtmpB13Tko/file_200.txt
[ =======>                          ] 4% 

EDIT 2

После окончания награды ничего не приближается к ожидаемому результату.

Вход в панель выполнения помешает всему. Если кто-то получит правильный результат, я дам еще одну награду за результат.

Ответы

Ответ 1

Здесь решение (не идеально) с использованием пользовательской функции.

Эта функция выводится на панель выполнения (используя message).

  • ii - текущая итерация.
  • N - общее количество итераций для выполнения.
  • per - шаг (процент), когда обновляется индикатор выполнения. Нам это нужно, так как при выполнении нескольких итераций индикатор выполнения обновляется слишком часто, а вывод испорчен.

Функция:

progBar <- function(ii, N, per = 10) {
    if (ii %in% seq(1, N, per)) {
        x <- round(ii * 100 / N)
        message("[ ", 
                paste(rep("=", x), collapse = ""),
                paste(rep("-", 100 - x), collapse = ""), 
                " ] ", x, "%", "\r",
                appendLF = FALSE)
    }
}

Код для проверки:

library(doMC)
library(foreach)
registerDoMC(10)

nIteration <- 1e3
foreach(i = 1:nIteration, ii = icount()) %dopar% {
    # For progBar ii I'm using icount(), because
    # user might iterate over all kind of objects
    progBar(ii, nIteration)
    Sys.sleep(1 / 10)
}

enter image description here

PS: Это не идеально, потому что:

  • Бар не всегда работает до 100% (в зависимости от количества итераций он может остановиться на 99%)
  • Иногда выход беспорядок (зависит от количества итераций и того, как часто они переключаются) - все еще отлаживая эту часть
  • Консоль не сбрасывается, если вы используете print/cat внутри foreach

Ответ 2

Вы можете сослаться на эту ссылку Параметр Прогресс параллельный для нескольких прозрений (может быть, не точное решение), которые помогут создать параллельный параллелизм.

txtProgressBar работает только тогда, когда тип 2 или 3

library("foreach")
library("doParallel")
library("progress")

registerDoParallel(parallel::makeCluster(7, outfile = ""))

pb <- progress_bar$new(
            format = " [:bar] :percent in :elapsed",
            total = 30, clear = FALSE, width = 80, force = T)
a <- foreach (i  = 1:30) %dopar% {
    pb$tick()
    Sys.sleep(0.5)
}


pb <- txtProgressBar(title = "Iterative training", min = 0, max = 30, style = 3)

foreach (i  = 1:30) %dopar% {
    setTxtProgressBar(pb, i)
    Sys.sleep(0.5)
}

См. Эту ссылку. Мониторинг функции с индикатором выполнения для разных способов выполнения индикатора выполнения в зависимости от потребностей.

Использование Multicore: позже вы можете зарегистрировать другой параллельный сервер или удалить регистрацию doMC, зарегистрировав последовательный бэкэнд, вызвав функцию registerDoSEQ. Например, рассмотрим следующую программу

> x <- iris[which(iris[,5] != "setosa"), c(1,5)]
> trials <- 10000
> ptime <- system.time({
+ r <- foreach(icount(trials), .combine=cbind) %dopar% {
+ ind <- sample(100, 100, replace=TRUE)
+ result1 <- glm(x[ind,2]~x[ind,1], family=binomial(logit))
+ coefficients(result1)
+ }
+ })[3]
> ptime

Ответ 3

Пакет, который я использовал, который делает это параллельно для обработки списков, - это pbmcapply, надеюсь, что это поможет.