【问题标题】:R: The foreach does not work with exporting figure out, such as png or ggsaveR:foreach 不适用于导出图形,例如 png 或 ggsave
【发布时间】:2019-08-27 21:04:04
【问题描述】:

我正在尝试在我的本地机器上运行 foreachdoParallel(Mac Pro 2009 有 12 核或 Macbook Pro 2017)。一旦出现 plot 或 device-out,例如 png 或 ggsave,foreach 就会卡住 --- 死锁。

2019 年 8 月 29 日更新:我做了一个简单的测试:

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]])
# }

第一个并行循环 ret.plot=... 有效,它导出四个 .txt 文件,并返回 ggplot 结果列表。 第二个循环,for(i in 1:4)foreach%do% 都能正常工作。 但是,第三个循环,foreach%dopar% 再次卡住。

所以它表明 1)并行在我的机器上工作正常,2)绘图函数(base::plotggsave)和并行之间可能存在兼容问题。

Mac 上的活动监视器显示四个 rsession 正在后台运行,并且 CPU 风扇工作得更加努力。 Terminal 或 RStudio 中的 R 没有区别。


原问题描述:

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)
}

没有错误,但程序在foreach处停止。

Test1:如果我只运行fxp() 并关闭plot(1:10),程序就可以工作。

Test2:如果我只运行fxg() 并关闭ggsave,程序就可以工作。

Test3:一旦plotggsave为ON,程序在foreach中进入死锁。

在另一台具有相同代码的 Linux 机器(集群机器)上进行的测试始终可以正常工作。 Linux集群的会话信息为:

R 版本 3.6.1 (2019-07-05) 平台:x86_64-pc-linux-gnu (64-bit) 运行于:Ubuntu 18.04.3 LTS

矩阵产品:默认 BLAS:
/usr/lib/x86_64-linux-gnu/openblas/libblas.so.3 LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.2.20.so

语言环境:[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

附加的基础包:[1] 并行统计图形 grDevices utils 数据集方法 [8] 基础

其他附加包:[1] ggplot2_3.2.1 doParallel_1.0.15 iterators_1.0.12 foreach_1.4.7

通过命名空间加载(未附加):[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.0pillar_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


【问题讨论】:

  • 尝试使用 cl = detectCores() -1 运行,看看是否复制了错误。如果您的机器在 MAC 中只有 4 核,您可能会耗尽所有资源。
  • 感谢您的建议。没有什么不同的。如果我使用一个核心(仅,它可以工作。如果我将 %dopar% 更改为 %do%,它可以工作。
  • 好的。我们消除了这一点。我认为另一个关键步骤是在每个集群内本地加载包。所以请在 foreach 中添加库(ggplot2)。 x=foreach(i =1:4, .packages = c("ggplot2")) %dopar% 等。之后请按原样运行代码。如果不成功,请依次重复测试 1-3 以了解此更改如何响应。
  • 由于您使用的是 registerDoParallel(4) 并且在 macOS 上(在 Linux 上也是如此),因此您最终会得到类似于 parallel::mclapply()forked 并行处理。如果您可以单独使用parallel::mclapply() 重现此问题,则可以排除 foreach/doParallel 是问题所在。
  • 谢谢。 @HenrikB。经过更多测试,我知道并行代码在没有任何绘图功能的情况下运行良好。一旦有 plot() 或 ggsave(),并行永远不会结束。

标签: r ggplot2 foreach parallel-processing


【解决方案1】:

我预计在 Mac OS 上的 %dopar% 中使用 png() 会出现同样的问题(Linux 和 Windows 都可以正常工作)。

这是由于 Mac Os 上的分叉机制和图形设备(可能还有 png() 实现)。
如果你做一些这样的事情,你会看到 png 没有创建新的图形设备:

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

## quartz_off_screen
##               2

似乎“quartz”在fork模式下无法打开新的图形设备。
让我们试试“Xlibpng(type="Xlib"),多么可爱的消息:

“分叉的孩子不应该打开图形设备”

这证实了我们的怀疑......但它“不应该”而不是“不能

解决方案

使用 1 个核心

将 %dopar% 与 1 核心作品一起使用,但这不是很有用。

cl <- 1
registerDoParallel(cl)

让我们试试“cairo”:

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

它正在工作! (对于我在 Mac OS 上)

【讨论】:

  • 谢谢杰弗瑞。是的,我应该使用 type='cairo'。除了你的建议,我必须使用 r-project.org 的 R 而不是 homebrew。
【解决方案2】:

感谢@jfrey,你是对的。我必须使用开罗。此外,它需要 X11。

这是我发现并解决了我的问题的东西。 1. 从 r-project 安装 R 而不是 homebrew。 2. 按照 jfrey 的建议,type = 'cairo'。

我的 Mac 上的 R 是从自制软件安装的,所以 capabilities() 返回 X11=FALSE。 然后我从 homebrew 中卸载了 R,然后从https://cran.r-project.org/bin/macosx/ 下载并安装了 R for Mac。然后capabilities() 返回X11=TRUE

然后 type='cairo' 的并行代码在我的 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 

一个线程可能有用:RStudio on Mac OS X 10.13 getting X11 is not available error when trying to use fix()

我通过代码漏洞确认:

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)
}

【讨论】:

    猜你喜欢
    • 2011-08-05
    • 2022-01-03
    • 2019-05-29
    • 2023-03-08
    • 2021-11-10
    • 2020-03-15
    • 1970-01-01
    • 2012-11-19
    • 2013-05-04
    相关资源
    最近更新 更多