【问题标题】:foreach() garbage collectionforeach() 垃圾回收
【发布时间】:2011-12-21 05:58:24
【问题描述】:

我正在使用 doSMP 包中的嵌套 foreach 来根据我开发的函数生成结果。通常问题会使用三个嵌套循环,但是由于生成的结果的大小(每个 i 大约 80,000 个),当最终结果矩阵超过指定的行数时,我不得不暂停编译并将结果写入文件。

i = 1
write.off = 1

while(i <= length(i.vector)){
        results.frame = as.data.frame(matrix(NA, ncol = 3, nrow = 1))

        while(nrow(results.frame) < 500000 & i <= length(i.vector)){
                results = foreach(j = 1:length(j.vector), .combine = "rbind", .inorder = TRUE) %:%
                foreach(k = 1:length(k.vector), .combine = "rbind", .inorder = TRUE) %dopar%{

                        ith.value = i.vector[i]
                        jth.value = j.vector[j]
                        kth.value = k.vector[k]
                        my.function(ith.value, jth.value, kth.value)
                }

                results.frame = rbind(results.frame, results)
                i = i + 1
        }

        results.frame = results.frame[-1,]
        write.table(results.frame, paste("part_",write.off, sep = ""))
        write.off = write.off + 1   
}

我遇到的问题是垃圾收集。工作人员似乎没有将内存重新分配回系统,因此在 i = 4 时,他们每个人都消耗了大约 6GB 的内存。

我尝试将 gc() 直接插入到 foreach 循环以及底层函数中,并且我还尝试将函数及其结果分配给我可以定期清除的命名环境。这些方法都没有奏效。

我觉得 foreach 的 initEnvir 和 finalEnvir 参数可能会提供一个解决方案,但文档和示例并没有真正说明这一点。

我在运行 Windows Server 2008 的 VM 上运行此代码。

【问题讨论】:

  • 如果您知道要填充多少行(即长度(i.vector)),您可以通过设置 results.frame 一次来节省大量时间和内存。每次通过做 rbind 或其他事情需要大量的 cpu 工作。看看矢量化更好。另外:你真的应该使用 &lt;- 而不是 = 。相信我们:-)
  • 我还要指出,由于外循环是i &lt;= length(i.vector),因此在内循环中没有使用相同的条件。花点时间弄清楚你真正想在这里做什么。
  • 外部 while 循环是为了让代码一直运行,直到它碰到 i.vector 中的最后一个元素(超过 1.8M)。第二个循环的原因是中断计算并定期保存结果。第二个 while 循环中的 i
  • 我有同样的问题,有时我不得不杀死我所有的 R 进程,因为它们正在吃服务器 RAM (512 Gb)。

标签: r garbage-collection parallel-processing


【解决方案1】:

您可以考虑通过编写不同的循环来完全避免这个问题。

考虑在AlgDesign 中使用gen.factorial 函数,呵呵:

fact1 = gen.factorial(c(length(i.vector), length(j.vector), length(k.vector)), nVars = 3, center = FALSE)
foreach(ix_row = 1:nrow(fact1)) %dopar% {
  my.function(fact1[ix_row,])
}

您还可以使用内存映射文件并使用 bigmemory 预分配输出存储空间(假设您正在创建一个矩阵),这样每个工作人员都可以自行存储其输出。

通过这种方式,您的整体内存使用量应该会大幅下降。


更新 1:内存问题似乎是 doSMP 特有的。查看以下帖子:

我记得在问题或 R 聊天中看到 doSMP 的另一个内存问题,但我似乎无法恢复帖子。

更新 2:我不知道这是否会有所帮助,但您可以尝试使用明确的 return()(例如 return(my.function(ith.value, jth.value, kth.value)))。在我的代码中,为了清楚起见,我通常使用显式的return()

【讨论】:

  • 感谢您的建议,但我的问题是工作人员(Rterm 进程)用完的内存。这个问题一般适用于 foreach。我能够让工作人员释放内存的唯一方法是通过 stopWorkers()。
  • 我想知道这是否是 Windows 和doSMP 上的问题。在我使用 doMC 在 Linux 上的工作中,我没有注意到任何类似的内存泄漏。顺便说一句,foreach 是一个单独的包,doSMPdoMC 是后端。
  • 现在我想起来了,其他人已经提到了 doSMP 的内存问题。我会修改我的答案以链接到他们。
  • 感谢后续迭代器。我浏览了帖子并尝试使用显式返回,但可惜无济于事。
  • 也许这应该与革命(即维护者)一起提出?如果您有解决方案,请发布! :)
猜你喜欢
  • 2012-01-28
  • 2013-06-27
  • 2011-11-29
  • 2021-12-20
  • 2011-07-15
  • 2014-03-09
  • 2013-06-10
  • 2010-11-05
  • 1970-01-01
相关资源
最近更新 更多