并行使用 rJava 和 xlsx

Using parallel alongside rJava and xlsx

我有一个巨大的 excel 文件要处理。我需要读取大量单元格的颜色和样式,并想通过并行化任务来加快计算速度。我依靠 xlsx 包及其函数 getCellStyle 逐个单元格地获取样式。反过来,该软件包依赖于 rJava。看起来,由于某种原因,涉及 java 个对象的任务无法并行化。这是一个可重现的例子:

require(xlsx)
require(writexl)
require(doParallel)
require(foreach)
require(parallel)

#We create an excel file with the iris dataset
filename <- "iris.xlsx"
write_xlsx(iris, filename)
#Read the workbook and the first (and only) sheet
wb <- loadWorkbook(filename)
sheet <- getSheets(wb)[[1]]
#With the next two rows we grab all the cells as Java objects
rows  <- getRows(sheet)
allcells <- getCells(rows)
#This works: grabbing the style
styles <- lapply(allcells, getCellStyle)
styles[[1]]
#[1] "Java-Object{org.apache.poi.xssf.usermodel.XSSFCellStyle@abd07bb0}"

#Now we try to go parallel: we create a cluster and make
#use of foreach and dopar
registerDoParallel(6)
stylePar<-foreach(i = seq_along(allcells)) %dopar% getCellStyle(allcells[[i]])
#Unfortunately, every Java object looks null
stylePar[[1]]
#[1] "Java-Object<null>"
#For the record, even mclapply returns all Java null objects
#mclapply(allcells, getCellStyle, mc.cores = 6, mc.preschedule = FALSE)

我是不是遗漏了什么,或者说 foreach 无法与 Java 对象一起使用?考虑到我只是在读取值而不是设置它们。

TLDR: 我认为初始化 wb inside foreach 循环应该可以解决你的问题。

R 中的并行包以一种相当简单的方式处理并行处理:它启动多个 R 实例,将必要的数据复制到每个实例中,运行您的代码,然后 returns 您的结果。

我怀疑您 运行 遇到的问题是 R 并不真正知道如何将 rJava 对象复制到 R 的新实例中。

我比较熟悉 futurefuture.apply。用 foreach 代替 future.apply 似乎可行。对象匹配 base::lapply

require(xlsx)
require(writexl)
#require(doParallel)
#require(foreach)

library(future.apply)

#We create an excel file with the iris dataset
filename <- "iris.xlsx"
write_xlsx(iris, filename)
#Read the workbook and the first (and only) sheet
wb <- loadWorkbook(filename)
sheet <- getSheets(wb)[[1]]
#With the next two rows we grab all the cells as Java objects
rows  <- getRows(sheet)
allcells <- getCells(rows)
#This works: grabbing the style
styles <- lapply(allcells, getCellStyle)
styles[[1]]
#[1] "Java-Object{org.apache.poi.xssf.usermodel.XSSFCellStyle@abd07bb0}"

# Specify how to parallize
plan(multisession)

# Apply getCellStyle to every object in allcells
stylePar <- future_lapply(allcells, getCellStyle)
stylePar[[1]]

styles[[1]] == stylePar[[1]]
#Now we try to go parallel: we create a cluster and make
#use of foreach and dopar
# registerDoParallel(6)
# stylePar<-foreach(i = seq_along(allcells)) %dopar% xlsx::getCellStyle(allcells[[i]])
# #Unfortunately, every Java object looks null
# stylePar[[1]]



由于其他解决方案没有指出这一点,我们不得不声明这是不可能的。
我在 R 邮件列表中找到了 8 年前的相同主题。

https://stat.ethz.ch/pipermail/r-devel/2013-November/067960.html

“这是 Java 运行时的限制 - 你不能派生 JVM。”

其他来源:how to fork JVM?

所以这不是 R 的限制,更多的是 JVM。

library(future.apply) 下的解决方案正在运行,因为已激活任何计划,因此使用了基础 lapply。应该像这样调用:

library(future)
library(future.apply)
plan(multisession)

最后要评论的是,多处理并不是那么微不足道,可以在不同的范例下工作。请查看未来的小插图 https://cran.r-project.org/web/packages/future/vignettes/future-1-overview.html。您可以找出同步和异步处理。不仅如此,每个人都有自己的区别。对我而言,重要的是要记住我们有 multisessionmulticore (multithreating),它们的工作方式截然不同。