1
votes

I am trying to run foreach and doParallel in my local machine (Mac Pro 2009 with 12 cores or Macbook Pro 2017). Once there is plot or device-out, such as png or ggsave, the foreach stucked --- deadlock.

UPDATE on Aug 29 2019: I made a simple test:

library(foreach)
library(doParallel)
library(ggplot2)
registerDoParallel(cores = 4)
ret.plot=foreach(i = 1:4) %dopar% {
  write(1:1, paste0(i, '_p.txt'))
  md=data.frame(x=1:10, y=1:10); 
  p=ggplot(md, aes(x=x, y=y))+geom_point();
}

# for(i in 1:4){
ret.save1=foreach(i = 1:4) %do% {
  ggsave(filename = paste0(i, '_do.png'), ret.plot[[i]])
}

ret.save2=foreach(i = 1:4) %dopar% {
  ggsave(filename = paste0(i, '_dopar.png'), ret.plot[[i]])
}

# ret.save2=foreach(i = 1:4, .packages = c("ggplot2")) %dopar% {
#   ggsave(filename = paste0(i, '_dopar.png'), ret.plot[[i]])
# }

The 1st parallel loop ret.plot=... works, that exports four .txt files, and return the list of ggplot results. The 2nd loop, both for(i in 1:4) or foreach with %do% work pefectly. BUT, the 3rd loop, foreach with %dopar% stucks again.

So it indicates 1)the parallel works alright in my machine, and 2) there may be a compatible issue between plot functions (base::plot or ggsave) and parallel.

The activity monitor on Mac shows four rsession are runing background and the CPU fan works harder. There is no difference in R in Terminal or RStudio.


Original question description:

Session information:

> sessionInfo() R version 3.6.1 (2019-07-05) Platform:
> x86_64-apple-darwin17.7.0 (64-bit) Running under: macOS High Sierra
> 10.13.6
> 
> Matrix products: default BLAS:  
> /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
> LAPACK: /usr/local/Cellar/openblas/0.3.7/lib/libopenblasp-r0.3.7.dylib
> 
> locale: [1]
> en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
> 
> attached base packages: [1] parallel  stats     graphics  grDevices
> utils     datasets  methods   base     
> 
> other attached packages: [1] ggplot2_3.2.1     doParallel_1.0.15
> iterators_1.0.12  foreach_1.4.7    
> 
> loaded via a namespace (and not attached):  [1] Rcpp_1.0.1      
> codetools_0.2-16 withr_2.1.2      assertthat_0.2.1  [5] dplyr_0.8.3   
> crayon_1.3.4     R6_2.4.0         grid_3.6.1        [9] gtable_0.3.0  
> magrittr_1.5     scales_1.0.0     pillar_1.4.2     [13] rlang_0.4.0   
> lazyeval_0.2.2   rstudioapi_0.10  tools_3.6.1      [17] glue_1.3.1    
> purrr_0.3.2      munsell_0.5.0    compiler_3.6.1   [21]
> pkgconfig_2.0.2  colorspace_1.4-1 tidyselect_0.2.5 tibble_2.1.3



library(foreach)
library(doParallel)
library(ggplot2)
fxp<- function(x){
  png(paste0(x, '_p.png')) ;
  plot(1:10);
  dev.off()
}
fxg <-function(x){ 
  md=data.frame(x=1:10, y=1:10); 
  p=ggplot(md, aes(x=x, y=y))+geom_point();
  ggsave(filename = paste0(x, '_g.png'), p)
}
fxp(0);fxg(0)

cl <- 4
registerDoParallel(cl)
x=foreach(i =1:4) %dopar% {
  # for( i in 1:2){
  fxp(i);
  fxg(i)
}

There is no error, but program stops in the foreach.

Test1: If I run fxp() only and turn plot(1:10) OFF, the program works.

Test2: If I run fxg() only and turn ggsave OFF, the program works.

Test3: Once plot or ggsave is ON, the program enter deadlock in the foreach.

The test on another Linux machine (a cluster machine) with identical code works correctly always. The session information of the Linux cluster is:

R version 3.6.1 (2019-07-05) Platform: x86_64-pc-linux-gnu (64-bit) Running under: Ubuntu 18.04.3 LTS

Matrix products: default BLAS:
/usr/lib/x86_64-linux-gnu/openblas/libblas.so.3 LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.2.20.so

locale: [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
[3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8 [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8 [7] LC_PAPER=en_US.UTF-8 LC_NAME=C [9] LC_ADDRESS=C LC_TELEPHONE=C [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C

attached base packages: [1] parallel stats graphics grDevices utils datasets methods [8] base

other attached packages: [1] ggplot2_3.2.1 doParallel_1.0.15 iterators_1.0.12 foreach_1.4.7

loaded via a namespace (and not attached): [1] Rcpp_1.0.2
codetools_0.2-16 withr_2.1.2 crayon_1.3.4 [5] grid_3.6.1
gtable_0.3.0 scales_1.0.0 pillar_1.4.2 [9] rlang_0.4.0
lazyeval_0.2.2 labeling_0.3 tools_3.6.1 [13] munsell_0.5.0 compiler_3.6.1 pkgconfig_2.0.2 colorspace_1.4-1 [17] tibble_2.1.3


2
Try running with cl = detectCores() -1 instead and see if you replicate the error. You may be depleting all your resources if your machine has only 4-cores in MAC.Vitali Avagyan
Thanks for your suggestion. It makes no difference. If I use one core ( only, it works. If I change the %dopar% to %do%, it works.Lele Shu
Ok. We eliminated that. I think another crucial step is to load packages locally inside each cluster. So please add library(ggplot2) inside foreach. x=foreach(i =1:4, .packages = c("ggplot2")) %dopar% etc. After this please run the code as it is. If unsuccessful, repeat your Test 1-3 sequentially to find out how this change responds.Vitali Avagyan
Since you're using registerDoParallel(4) and are on macOS (same on Linux), you're ending up with forked parallel processing similar to parallel::mclapply(). If you can reproduce this with parallel::mclapply() alone, you can rule out that foreach/doParallel is the problem.HenrikB
Thanks. @HenrikB. After more test, I know the parellel code works well without any plot functions. Once there is plot() or ggsave(), the parallel never end.Lele Shu

2 Answers

2
votes

I've expected the same issue using png() in a %dopar% on Mac OS (linux and Windows work fine).

This is somethings due to forking mechanism and graphics device on Mac Os (and maybe png() implementation).
If you do some things like this, you will see that no new graphics device is created by png:

fxp<- function(x){
    print(dev.cur())
    png(paste0(x, '_p.png')) ;
    print(dev.cur())
    plot(1:10);
    dev.off()
}

## quartz_off_screen
##               2

It seems that "quartz" can't open new graphic device in fork mode.
Let try with "Xlib" png(type="Xlib"), what a lovely message :

"a forked child should not open a graphics device"

This confirms our doubts... but it "should not" not "can't"

Solutions

Use 1 core

Use %dopar% with 1 core works but this is not very useful.

cl <- 1
registerDoParallel(cl)

So lets try with "cairo" :

fxp<- function(x){
    png(paste0(x, '_p.png'), type = "cairo", bg = "white") ;
    plot(1:10);
    dev.off()
}

It's working ! (for me on Mac OS)

0
votes

Thank @jfrey, You are right. I have to use cairo. Also, it require X11.

Here is something I found and solves my problem. 1. install R from r-project instead of homebrew. 2. type = 'cairo' as jfrey suggested.

The R on my Mac is installed from homebrew, so the capabilities() return X11=FALSE. Then I uninstalled the R from homebrew, then download and install the R for Mac from https://cran.r-project.org/bin/macosx/. Then the capabilities() returns X11=TRUE.

Then the parallel code with type='cairo' works perfectly on my Mac.

 capabilities()



     jpeg         png        tiff       tcltk         X11        aqua 
       TRUE        TRUE        TRUE        TRUE        TRUE        TRUE 
   http/ftp     sockets      libxml        fifo      cledit       iconv 
       TRUE        TRUE        TRUE        TRUE        TRUE        TRUE 
        NLS     profmem       cairo         ICU long.double     libcurl 
       TRUE        TRUE        TRUE        TRUE        TRUE        TRUE 

A thread might be useful: RStudio on Mac OS X 10.13 getting X11 is not available error when trying to use fix()

I confirmed with code blow:

library(foreach)
library(doParallel)
library(ggplot2)
fxp<- function(x){
  png(paste0(x, '_p.png'), type = "cairo") ;
  plot(1:10);
  dev.off()
}
fxg <-function(x){ 
  md=data.frame(x=1:10, y=1:10); 
  p=ggplot(md, aes(x=x, y=y))+geom_point();
  ggsave(filename = paste0(x, '_g.png'), p, type = "cairo")
}
fxp(0);fxg(0)

cl <- 4
registerDoParallel(cl)
x=foreach(i =1:4) %dopar% {
  fxp(i);
  fxg(i)
}