楼主: 黑白纯
3578 4

[问答] R语言内存耗尽,Error: memory exhausted (limit reached?) [推广有奖]

  • 0关注
  • 0粉丝

大专生

63%

还不是VIP/贵宾

-

威望
0
论坛币
20 个
通用积分
9.9145
学术水平
3 点
热心指数
3 点
信用等级
3 点
经验
525 点
帖子
30
精华
0
在线时间
48 小时
注册时间
2019-10-25
最后登录
2021-10-16

4论坛币
最近跑一个循环比较多的程序,需要执行两千多万次的基因比对以及二项式计算,之前一直用for循环跑,但是速度真的很慢,于是百度查了一下多线程的使用问题。发现parallel和foreach包可以实现多线程的操作,加快运行速度。通过detectCore()函数得知我的电脑能同时运行12个线程。于是先进行了检测,发现在1万次甚至10万次的循环中。12线程的foreach循环速度均要比单线程的foreach循环速度还要慢(用法是没出现错误的,多线程%dopar%,单线程%do%)。虽然可能每次只是慢了几秒钟。于是我怀疑是不是我没有成功打开多线程?但是多次检查程序也没发现有什么问题,程序如下

c1<-makeCluster(12)
registerDoParallel(c1)
ptm<-proc.time()
b<-foreach(i=c(1:10000),.combine = 'rbind') %dopar% {
  reverse_num<-sum(GSE9348[which(GSE9348[,1]==stable_pair[i,1]),2:GSE9348_num_patients]<GSE9348[which(GSE9348[,1]==stable_pair[i,2]),2:GSE9348_num_patients])
  dbinom(reverse_num,GSE9348_num_patients-1,0.01)#每个患者中该稳定对逆转的概率为0.01,在GSE9348_num_patients个患者中,该基因对出现逆转的次数为reverse_num,概率存在binom_pvalue[i,1]中
}
stopCluster(c1)
proc.time()-ptm


由于还是相信多线程的运算能力,所以最后我还是用多线程跑的前1000w个基因对(一共2000w个)。结果原本测试过程中1w次循环需要6.6s,理论上1000w次循环在2个小时内绝对可以跑完了,但是结果却大大出乎意料,1000w次的循环竟然跑了14个小时才结束。
然后我就想,是不是内存占用的原因导致的时间延长了这么多呢?又各种搜索资料找R内存相关的知识,感觉算是搜了个一知半解。得知看已占内存的方法memory.size(F)和清理内存的方法gc(),按照我的理解,在我没有增加变量名的情况下,也就不会增加新的变量,就不会出现新的变量导致内存不够的问题,R语言发现多余的堆积内存会自动执行gc()方法,能够清理R语言执行过程中产生的临时变量(这是我的理解,举个例子就是假如循环中有cbind,R会不断开拓内存空间存储新的matrix,导致内存累计,但是gc()应该能清理这些内存的堆积,但是我在之后的尝试中觉得我理解可能有误了,gc()方法好像并没有这么强大。

然后为了证明多线程确实能比单线程运行速度快,我在百度查了很多parallel的使用方法,但是都没给出具体的时间证据来证明foreach方法的多线程速度快于单线程,而parapply方法却有证据表明速度是快于Lapply的,其中发现了一个程序如下
square <- function(x)
{
  #########
  #一段冗余代码增加执行时间
  y = 2*x
  if(y <300)
  {z = y}
  else
  {z = x}
  ##########   
  return(x^2)
}
num <- c(1:10000000)
cl <- makeCluster(12) # 初始化四核心集群
system.time({
  results <- parLapply(cl,num,square)#调用parLapply并行计算平方函数
  final <- do.call('c',results)#整合结果
  stopCluster(cl) # 关闭集群
})

system.time({
  results <- lapply(num,square)
  final <- do.call('c',results)#整合结果
})

这个程序没涉及到foreach方法,但是得到的结果显示多线程的速度的确会高于单线程,我用电脑跑完发现多线程用时10s左右,单线程12s左右(我跑了很多次,每次结果都不一样,这里给了个大致的值)。我考虑到可能是因为num的范围还是不够大导致两种线程速度差异不明显,于是我将num由1000w增加至5000w 。然后跑了将近两分钟的时候上边多线程的方法就开始报错
Error: memory exhausted (limit reached?)
这时候我用memory.size(F)看了下R的已用内存显示
> memory.size(F)
[1] 3433.63

我设置的内存上限是8020M
> memory.limit()
[1] 8082

这么一看明明没有满,但是确保错内存耗尽?我以为有系统堆积的无用内存导致的这个原因,于是gc()之后,发现memory.size(F)还是3433.63 。然后我的人生观崩塌了
说了这么多,查了这么多,总结一下我的问题就是
1.多线程的foreach循环为什么会比单线程的foreach循环慢?
2.为什么1w次循环仅需要6.6s,但是1000w次的循环却需要14个小时?
3.已用内存仅仅是3433M,内存上限有8082M,为什么会出现内存耗尽的报错?
4.gc()清理的到底是什么?
对于R我了解的虽然少,但是希望能多跟前辈们学习,希望有大神能帮我解答,万分感谢!

关键词:R语言初学者 R语言程序请教 r语言程序问题 R语言
已有 1 人评分论坛币 收起 理由
万人往LVR + 5 问问题条理很清晰,同有多线程的问题

总评分: 论坛币 + 5   查看全部评分

沙发
nuomin 发表于 2020-3-7 21:46:07 |只看作者 |坛友微信交流群
分成两步试试吧,估计都不需要跑多核。先把对比的结果做成数据集文件,然后计算二项概率。
已有 1 人评分论坛币 收起 理由
cheetahfly + 10 热心帮助其他会员

总评分: 论坛币 + 10   查看全部评分

使用道具

藤椅
黑白纯 发表于 2020-3-8 00:33:20 |只看作者 |坛友微信交流群
nuomin 发表于 2020-3-7 21:46
分成两步试试吧,估计都不需要跑多核。先把对比的结果做成数据集文件,然后计算二项概率。
直接用for循环的话用时会比较久,之前试了下,等了好久没出结果。请问“对比的结果做成数据集文件”是什么意思呢,理解能力较差,抱歉

使用道具

板凳
nuomin 发表于 2020-3-8 21:34:42 |只看作者 |坛友微信交流群
这一条
reverse_num<-sum(GSE9348[which(GSE9348[,1]==stable_pair[i,1]),2:GSE9348_num_patients]<GSE9348[which(GSE9348[,1]==stable_pair[i,2]),2:GSE9348_num_patients])

使用道具

报纸
黑白纯 发表于 2020-3-9 00:18:11 |只看作者 |坛友微信交流群
nuomin 发表于 2020-3-8 21:34
这一条
reverse_num
可是就是这一条命令,需要跑很久才出结果,其实要的就是这个结果,为了让这个命令能尽快抛出结果才引发了我对多线程速度的思考。其实这个结果我现在已经得到了,关键还是下边那几个问题希望得到解答,1w次循环需要6.6s,理论上1000w次循环应该是6600s吧,也就是两个小时,为什么最后花了14个小时才跑完呢?感谢您的解答

使用道具

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加好友,备注cda
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-5-26 14:51