最近跑一个循环比较多的程序,需要执行两千多万次的基因比对以及二项式计算,之前一直用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.循环的过程中没有产生新的变量名,原本在上述程序运行前,memory.size仅仅为200多M,运行中途报错导致结果变量final没有出现为什么内存会堆积到3433M?
5.gc()清理的到底是什么?
对于R我了解的虽然少,但是希望能多跟前辈们学习,希望有大神能帮我解答,万分感谢!