foreachでprogressbarを表示しても進行状況は正しくないケースが多い

の辺でやられているforeach系パッケージでプログレスバーを出す方法だが、これは進捗を正しく表すものではないケースが多い*1

例えば、

library(foreach)
library(utils)
library(iterators)
library(doParallel)
cl <- makeCluster(4, type='SOCK')
registerDoParallel(cl)
f <- function(){
  pb <- txtProgressBar(min=1, max=n-1,style=3)
  count <- 0
  function(...) {
    count <<- count + length(list(...)) - 1
    setTxtProgressBar(pb,count)
    flush.console()
    c(...)
  }
}

n <- 100
# Run the loop in parallel
k <- foreach(i = seq(n), .final=c, .combine=f()) %dopar% {
  a <- rnorm(10^7)
  log2(i)
}

というコードを実行するとわかるが、全体の計算が終わった後、一気にプログレスバーが進むような挙動になり、
Combine(並列化したデータをまとめあげる処理)が全スレッド・全計算が終わってから走ってるような挙動に見える。


この辺は、下記のStackOverflowでも議論されており、

It won't work well with doParallel because doParallel only calls the combine function after all of the results have been returned, since it is implemented by calling the parallel clusterApplyLB function. This technique only with works well with backends that call the combine function on-the-fly, like doRedis, doMPI, doNWS, and (defunct?) doSMP.

という記述がある通り。
私もこれが正しいなと思い、やはりdoParallelがバックエンドだとコンバイン処理が最後にまとまってくるという解釈でよくプログレスバーを正しく出すのは難しいぞと*2

*1:並列化のバックエンド依存があるので、こういう物言いになっとる

*2:いう話を https://r-wakalang.slack.com/messages/r_chotowakaru/ でしていたのでそのまとめ