如何在R中并行化包含稀疏矩阵的算法

joe*_*237 6 parallel-processing r sparse-matrix

我一直在使用R中的库'doParallel'来提高一组函数的速度.但是,我遇到了一个我无法解决的错误.我相信以下代码隔离了问题的精髓:

library(Matrix)
library(doParallel)

test_mat = Matrix(c(0,1,2,NA,0,0,2,NA,1,NA,1,2,2,NA,0,1,0,2,2,2,0,0,NA,NA,1,2,1,1,2,1,rep(NA,5)), ncol=7, byrow=TRUE, sparse=TRUE)

par_func <- function(mat, ncores)
{
  cl <- makePSOCKcluster(ncores)
  clusterSetRNGStream(cl) 
  registerDoParallel(cl, cores = ncores)

  df = data.frame(1:7, NA)

  temp_vec = foreach(i=iter(df, by='row'), .combine=rbind) %dopar%
  {
    i[,2] <- sum(mat[,i[,1]] == 1, na.rm = TRUE) + 1
  }
  stopCluster(cl)
  return(temp_vec)
}

par_func(mat=test_mat, ncores=5)
Run Code Online (Sandbox Code Playgroud)

这会产生以下错误消息:

Error in { : task 1 failed - "object of type 'S4' is not subsettable" 
Run Code Online (Sandbox Code Playgroud)

如果'mat'是'matrix'类而不是'dgCMatrix',则此函数有效,因此问题似乎是由于稀疏矩阵的子集化.我有什么选择可以解决这个问题吗?矩阵"mat"可以非常大并且可以包含许多零,因此我想继续使用稀疏矩阵.

Ste*_*ton 7

根本问题是工作人员没有加载Matrix包,因此他们不知道如何将Matrix对象"mat"子集化.您可以使用foreach .packages选项解决此问题:

temp_vec = foreach(i=iter(df, by='row'), .packages='Matrix', .combine=rbind) %dopar% {
  # snip
}
Run Code Online (Sandbox Code Playgroud)

请注意,您的示例在所有平台上都失败,但是如果您要使用以下命令注册doParallel:

registerDoParallel(4)
Run Code Online (Sandbox Code Playgroud)

那么你的foreach循环可以在Linux和Mac OS X上运行,但在Windows上失败了!原因是在Linux和Mac OS X上,将使用mclapply函数,但在Windows上,将隐式创建一个集群对象,然后将使用clusterApplyLB函数.工作人员由mclapply分叉,因此他们继承了父项的环境,包括加载的包,因此foreach循环起作用.但是当使用makePSOCKcluster时,工作者不会继承环境,因此您必须使用.packages选项之类的东西来初始化工作者的环境,否则foreach循环将失败.具有讽刺意味的是,由于doParallel软件包隐藏了这种差异以使事情变得更容易,因此它为Windows用户设置了一个小的可移植性陷阱.

还有其他方法可以改进这个例子(正如@agstudy所提到的),但正如我所说,基本问题是Matrix包没有加载到worker上.