rプログラムでループのカウンターを作成する方法についての有益な投稿があります。しかし、「foreach()」で並列化されたバージョンを使用する場合、同様の関数をどのように作成しますか?
編集:doSNOWパッケージへの pdate の後、%dopar%
を使用すると、Niceプログレスバーを表示するのが非常に簡単になり、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)
進行状況を追跡するさらにもう1つの方法は、反復の総数を覚えている場合、.verbose = T
を設定することです。これにより、どの反復が終了したかがコンソールに出力されます。
LinuxおよびOS Xの以前のソリューション
Ubuntu 14.04(64ビット)およびOS X(El Capitan)では、makeCluster
関数で%dopar%
が設定されている場合、oufile = ""
を使用している場合でも進行状況バーが表示されます。 Windowsでは動作しないようです。 makeCluster
のヘルプから:
outfile:ワーカーからのstdoutおよびstderr接続出力の送信先。 ""はリダイレクトがないことを示します(ローカルマシンのワーカーにのみ役立つ場合があります)。デフォルトは「/ dev/null」(Windowsでは「nul:」)です。
コード例:
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)
これ は、進行状況バーの外観です。新しいバーがバーの進行ごとに印刷されるため、およびワーカーが少し遅れてプログレスバーがときどき前後に移動する可能性があるため、少し奇妙に見えます。
このコードは 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)
事前に、反復数と組み合わせ関数を知っておく必要があります。
これはparallel
パッケージで可能になりました。 "PSOCK"
タイプのクラスターを使用して、RStudio内で実行されているOSX 10.11上のR 3.2.3でテストされています。
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
でのみ正しく表示されます。
ループの前に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つずつプロセスに割り当てられることを意味します1つ前のアイテムが完成した順に並べます。
これをprogress
パッケージで動作させることもできます。
# 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)
このコードは、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)
}