【问题标题】:Is it possible to get a progress bar with foreach and a "multicore-kind" of backend是否有可能获得带有 foreach 和“多核类型”后端的进度条
【发布时间】:2018-12-15 05:36:42
【问题描述】:

在使用foreachdoMC 后端使用“多核”并行性时(我在查看它时使用 doMC,其他包不允许从我想获取进度条进行日志记录,使用progress 包,但任何进展(适用于 linux 终端,即没有 tcltk 弹出窗口)都可以。

鉴于它使用分叉,我可以想象这可能是不可能的,但我不确定。

预期用途是在我并行加载连接的 100 个文件时指示进度(通常在 #!Rscript 内)

我看过How do you create a progress bar when using the “foreach()” function in 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% 

编辑 2

在赏金结束后,没有什么能接近预期的结果。

在进度条中记录会使一切变得混乱。 如果有人得到正确的结果,我将给予另一个基于结果的赏金。

【问题讨论】:

标签: r progress-bar parallel-foreach domc


【解决方案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)
        if (ii == N) cat("\r")
    }
}

要测试的代码:

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:它并不完美,因为:

  • Bar 并不总是运行到 100%(取决于它可以在 99% 停止的迭代次数)
  • 有时输出会混乱(取决于迭代次数和切换频率) - 仍在调试这部分
  • 如果您在foreach 中使用print/cat,则不会刷新控制台

【讨论】:

  • 如果我使用 doParallel 而不是 doMC 可以吗
【解决方案2】:

您可以参考此链接Progress bar parallel 了解一些有助于创建平行进度条的见解(可能不是确切的解决方案)。

txtProgressBar 仅在 stype 为 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)
}

请参考此链接Monitoring the function with progress bar,了解根据需要实现进度条的不同方式。

使用多核: 您可以稍后注册不同的并行后端,或者通过调用 registerDoSEQ 函数注册顺序后端来取消注册 doMC。例如考虑以下程序

> 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

【讨论】:

  • 这不是使用多核并行吧?
  • @statquant.. 我已经用一个关于多核的小例子更新了上面的答案
  • 它在 Windows 10、R 3.6.1 上不起作用,我敢打赌这是操作系统问题。进度条不会前进,即使使用 flush.console()
【解决方案3】:

我使用的用于处理列表的并行包是pbmcapply,希望对您有所帮助。

【讨论】:

  • 好吧,我想保留我喜欢的 foreach 语法。这是一种多核类型的并行吗?
  • 它是多核的,它的操作方式与使用 lapply 的方式相同,但您还可以指定您想要使用的核心数量。我发现当想要在一个对象/数据帧列表上并行化一个函数时,它是最有益的,它的工作方式类似于 map,但是是并行的。 cran.r-project.org/web/packages/pbmcapply/index.html
  • 好的,这意味着它应该可以使用 foreach 然后
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-11-09
  • 1970-01-01
  • 2017-01-18
  • 1970-01-01
  • 1970-01-01
  • 2021-06-08
  • 1970-01-01
相关资源
最近更新 更多