我在一台拥有8个虚拟核心和8 GB RAM的Ubuntu工作站上运行R。我希望经常使用multicore包以并行地利用这8个核心; 但我发现整个R进程会被复制8次。
由于R似乎使用的内存比gc报告的多得多(即使在gc()之后,也是5倍),这意味着即使是相对较小的内存使用(一个200MB对象)在重复8次后也变得难以处理。
我考虑使用bigmemory让子进程共享相同的内存空间; 但它需要对我的代码进行一些重大改写,因为它不能处理数据框架。
有没有办法在分叉之前尽可能地精简R,即使操作系统重新获取尽可能多的内存?
编辑: 我现在认为我理解了发生了什么。问题不在我原以为的地方 - 存在于父线程中且未被操作的对象不会复制八次。相反,我认为我的问题来自于我让每个子进程执行的操作的性质。每个子进程都必须操作一个具有数十万级别的大要素,并且我认为这是占用内存最多的部分。因此,总内存负载确实与核心数量成比例; 但不像我想象的那样激烈。 我学到的另一个教训是,在拥有4个物理核心+可能的超线程的情况下,超线程实际上通常不适用于R。收益微乎其微,而内存成本可能是非常重要的。因此,从现在开始我将使用4个核心。
对于那些想要实验的人,这是我正在运行的代码类型:
有没有办法在分叉之前尽可能地精简R,即使操作系统重新获取尽可能多的内存?
编辑: 我现在认为我理解了发生了什么。问题不在我原以为的地方 - 存在于父线程中且未被操作的对象不会复制八次。相反,我认为我的问题来自于我让每个子进程执行的操作的性质。每个子进程都必须操作一个具有数十万级别的大要素,并且我认为这是占用内存最多的部分。因此,总内存负载确实与核心数量成比例; 但不像我想象的那样激烈。 我学到的另一个教训是,在拥有4个物理核心+可能的超线程的情况下,超线程实际上通常不适用于R。收益微乎其微,而内存成本可能是非常重要的。因此,从现在开始我将使用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))
))
tapply(x, f, sum)
中,f
被强制转换为因子,并且每个迭代大约需要1/2的时间。因此,在循环外将其作为因子可以加快计算速度并避免重复,从而减少内存使用。另外,tapply
的一个显著成本是简化结果,我们可以使用unlist(lapply(split(x, f), sum), use.names=FALSE)
自己完成这项工作(以更脆弱的代码为代价)。这些操作可以导致5-6倍的加速,至少节省3年的时间! - Martin Morgan