当前位置: 首页>>技术教程>>正文


Ubuntu下R中的多核和内存使用情况

, ,

问题描述

我在Ubuntu工作站上运行R,它有8个虚拟内核和8 Gb内存。我希望经常使用多核软件包来并行使用8个核心;但是我发现整个R过程重复了8次。由于R实际上似乎使用了比gc中报告的更多的内存(通过因子5,甚至在 gc()之后),这意味着即使相对温和的内存使用(一个200Mb对象)也会变得难以处理memory-heavy一次重复8次。我调查了bigmemory让子进程共享相同的内存空间;但它需要对我的代码进行一些重大改写,因为它不处理数据帧。

有没有办法在分叉之前使R尽可能精简,即让OS回收尽可能多的内存?

编辑:我想我明白现在发生了什么。问题不在我想象的地方 – 父线程中存在且未被操纵的对象不会重复八次。相反,我的问题来自于我正在使每个子进程执行的操作的性质。每个都必须操纵一个具有数十万个级别的重要因素,我认为这是memory-heavy位。结果,确实存在总存储器负载与核心数成比例的情况;但没有我想象的那么戏剧化。我学到的另一个教训是,有4个物理内核+超线程的可能性,超线程实际上对于R来说通常不是一个好主意。增益很小,内存成本可能是non-trivial。所以我从现在开始研究4核。

对于那些想要试验的人来说,这是我运行的代码类型:

# Create data
sampdata <- data.frame(id = 1:1000000)
for (letter in letters) {
sampdata[, letter] <- rnorm(1000000)
}
sampdata$groupid = ceiling(sampdata$id/2)

# Enable multicore
library(multicore)
options(cores=4) # number of cores to distribute the job to

# Actual job
system.time(do.call("cbind", 
    mclapply(subset(sampdata, select = c(a:z)), function(x) tapply(x, sampdata$groupid, sum))
))

最佳解决办法

你试过data.table吗?

> system.time(ans1 <- do.call("cbind",
lapply(subset(sampdata,select=c(a:z)),function(x)tapply(x,sampdata$groupid,sum))
))
   user  system elapsed 
906.157  13.965 928.645 

> require(data.table)
> DT = as.data.table(sampdata)
> setkey(DT,groupid)
> system.time(ans2 <- DT[,lapply(.SD,sum),by=groupid])
   user  system elapsed 
186.920   1.056 191.582                # 4.8 times faster

> # massage minor diffs in results...
> ans2$groupid=NULL
> ans2=as.matrix(ans2)
> colnames(ans2)=letters
> rownames(ans1)=NULL

> identical(ans1,ans2)
[1] TRUE

你的例子非常有趣。它相当大(200MB),有很多组(1/2万),每组很小(2行)。 191s可能会有很大改善,但至少它是一个开始。 [2011年3月]


现在,这个成语(即lapply(.SD,...))已经得到了很大的改进。使用v1.8.2,并且在比上面测试更快的计算机上,以及最新版本的R等,这里是更新的比较:

sampdata <- data.frame(id = 1:1000000)
for (letter in letters) sampdata[, letter] <- rnorm(1000000)
sampdata$groupid = ceiling(sampdata$id/2)
dim(sampdata)
# [1] 1000000      28
system.time(ans1 <- do.call("cbind",
  lapply(subset(sampdata,select=c(a:z)),function(x)
    tapply(x,sampdata$groupid,sum))
))
#   user  system elapsed
# 224.57    3.62  228.54
DT = as.data.table(sampdata)
setkey(DT,groupid)
system.time(ans2 <- DT[,lapply(.SD,sum),by=groupid])
#   user  system elapsed
#  11.23    0.01   11.24                # 20 times faster

# massage minor diffs in results...
ans2[,groupid:=NULL]
ans2[,id:=NULL]
ans2=as.matrix(ans2)
rownames(ans1)=NULL

identical(ans1,ans2)
# [1] TRUE

sessionInfo()
R version 2.15.1 (2012-06-22)
Platform: x86_64-pc-mingw32/x64 (64-bit)

locale:
[1] LC_COLLATE=English_United Kingdom.1252   LC_CTYPE=English_United Kingdom.1252
[3] LC_MONETARY=English_United Kingdom.1252  LC_NUMERIC=C
[5] LC_TIME=English_United Kingdom.1252

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

other attached packages:
[1] data.table_1.8.2 RODBC_1.3-6     

次佳解决办法

我在Ubuntu 64位R上尝试过的事情,按成功顺序排列:

  • 正如您所做的那样,使用更少的内核。

  • 将mclapply作业拆分为多个部分,并使用带有append = TRUE的DBI将部分结果保存到数据库。

  • 经常使用rm功能和gc()

我已经尝试了所有这些,并且mclapply仍然开始创建越来越大的进程,因为它运行,导致我怀疑每个进程都保留了它真正不需要的某种剩余内存。

附:我正在使用data.table,似乎每个子进程都复制data.table。

参考资料

本文由Ubuntu问答整理, 博文地址: https://ubuntuqa.com/article/6637.html,未经允许,请勿转载。