Search code examples
rparallel-processingapply

parSapply and progress bar


I am using the function parSapply to run a simulation on the parallel environment. Here is my code:

runpar <- function(i) MonteCarloKfun(i=i)

# Detect number of cores available
ncores <- detectCores(logical=TRUE)

# Set up parallel environment
cl <- makeCluster(ncores, methods=FALSE)

# Export objects to parallel environment
clusterSetRNGStream(cl,1234567) # not necessary since we do not sample
clusterExport(cl, c("kfunctions","frq","dvec","case","control","polygon", "MonteCarloKfun", "khat", 
                    "as.points", "secal"))

# For 1 parameter use parSapply
outpar <- parSapply(cl,i,runpar)

# close parallel environment
stopCluster(cl)

Does anyone know if there is a possibility to add a progress bar to the parSapply function. Ideally I would like something similar to pbapply of the pbapply library.


Solution

  • The parSapply function doesn't support a progress bar, and I don't think there is any really good way to implement one by adding extra code to the task function, although people have made valiant efforts to do that.

    The doSNOW package supports progress bars, so you could either use that directly or write a wrapper function that works like the parSapply function. Here's one way to write such a wrapper function:

    # This function is similar to "parSapply", but doesn't preschedule
    # tasks and doesn't support "simplify" and "USE.NAMES" options
    pbSapply <- function(cl, X, FUN, ...) {
      registerDoSNOW(cl)
      pb <- txtProgressBar(max=length(X))
      on.exit(close(pb))
      progress <- function(n) setTxtProgressBar(pb, n)
      opts <- list(progress=progress)
      foreach(i=X, .combine='c', .options.snow=opts) %dopar% {
        FUN(i, ...)
      }
    }
    

    You can easily modify this function to use either the tkProgressBar or winProgressBar function.

    Here's an example use of pbSapply:

    library(doSNOW)
    cl <- makeSOCKcluster(3)
    x <- pbSapply(cl, 1:100, function(i, j) {Sys.sleep(1); i + j}, 100)
    

    Note that this doesn't use prescheduling, so the performance won't be as good as parSapply if you have small tasks.