Можно ли получить индикатор выполнения с foreach и "многоядерным" бэкэндом
При использовании "многоядерного" параллелизма с использованием foreach и бэкэнда doMC (я использую doMC, так как в то время, когда я просматривал его, другой пакет не позволял входить в систему из-за того, что я хотел бы получить индикатор выполнения, используя пакет выполнения, но любой прогресс (это работает на терминале Linux, то есть без tcltk всплывающих окон) не может сделать.
Учитывая, что он использует разветвление, я могу представить, что это невозможно, но я не уверен.
Предполагаемое использование состоит в том, чтобы указать прогресс, когда я параллельно загружаю сотни файлов (обычно в #!Rscript)
Я посмотрел несколько постов типа Как создать индикатор выполнения при использовании функции "foreach()" в R?, Рад присуждать награду за это.
РЕДАКТИРОВАТЬ
Награда в 500 баллов за того, кто показывает мне, как
- использование foreach и многоядерный (разветвленный) тип параллелизма
- получить индикатор выполнения
- получить запись с помощью 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%
РЕДАКТИРОВАТЬ 2
После того, как награда закончилась, ничто не приближается к ожидаемому результату.
Вход в индикатор выполнения все портит. Если кто-то получит правильный результат, я дам еще одну награду, основанную на результатах.
3 ответа
Вот решение (не идеальное) с использованием пользовательских функций.
Эта функция выводит на консоль (используя 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)
}
PS: это не идеально, потому что:
- Бар не всегда бежит к
100%
(в зависимости от количества итераций он может остановиться на99%
) - Иногда выходные данные портятся (зависит от количества итераций и частоты их переключения) - все еще отлаживая эту часть
- Консоль не сбрасывается, если вы используете
print
/cat
вforeach
Вы можете обратиться к этой ссылке Параллель хода выполнения для нескольких идей (может быть, не точное решение), которые помогут в создании параллели индикатора выполнения.
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)
}
См. Эту ссылку. Мониторинг функции с индикатором выполнения для различных способов реализации индикатора выполнения в зависимости от потребностей.
Использование многоядерности: позже вы можете зарегистрировать другой параллельный бэкэнд или отменить регистрацию 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
Пакет, который я использовал для параллельной обработки списков, pbmcapply
, надеюсь это поможет.