我在函数内部的循环中有一个函数。内部函数在内存中获取并存储大量数据(作为全局变量......我使用“R”,类似于“S-Plus”)。循环遍历要获取的长数据列表。外部函数启动该过程并传入要获取的数据集列表。
for (dataset in list_of_datasets) {
for (datachunk in dataset) {
<process datachunk>
<store result? as vector? where?>
}
}
我编写了内部函数来存储每个数据集,然后再移动到下一个数据集,因此外部函数的所有工作都作为全局变量的副作用发生...一个大禁忌。这比收集和返回一个巨大的,占用记忆的向量矢量更好还是更糟?是否有优越的第三种方法?
如果我将数据向量存储在数据库而不是内存中,答案会改变吗?理想情况下,我希望能够终止该功能(或由于网络超时而使其失败),而不会丢失在终止之前处理的所有信息。
答案 0 :(得分:9)
在外部函数中使用变量而不是全局变量。这将为您提供两种方法中的最佳方法:您不会改变全局状态,也不会复制大量数据。如果您必须提前退出,只需返回部分结果。
(参见R手册中的“范围”部分:http://cran.r-project.org/doc/manuals/R-intro.html#Scope)
答案 1 :(得分:6)
记住你的Knuth。 “过早优化是所有编程邪恶的根源。”
试试副作用免费版。看它是否符合您的性能目标。如果确实如此,那么首先你没有问题;如果没有,那么使用副作用,并为下一个程序员记下你的手被迫。
答案 2 :(得分:4)
这对内存使用没有太大影响,所以你不妨让代码干净。
由于R对变量具有copy-on-modify,因此修改全局对象将具有与在返回值中传递内容相同的内存含义。
如果将输出存储在数据库中(甚至存储在文件中),则不会出现内存使用问题,并且数据将在创建时逐步可用,而不是仅在最后。数据库的速度是否更快主要取决于您使用的内存量:减少垃圾收集是为了支付写入磁盘的成本。
R中有时间和内存分析器,因此您可以凭经验查看影响。
答案 3 :(得分:1)
我不确定我是否理解这个问题,但我有几个解决方案。
在函数内部,创建一个向量列表并返回该向量。
在函数内部,创建一个环境并存储其中的所有向量。只要确保在出现错误时返回环境。
help(environment)
# You might do something like this:
outer <- function(datasets) {
# create the return environment
ret.env <- new.env()
for(set in dataset) {
tmp <- inner(set)
# check for errors however you like here. You might have inner return a list, and
# have the list contain an error component
assign(set, tmp, envir=ret.env)
}
return(ret.env)
}
#The inner function might be defined like this
inner <- function(dataset) {
# I don't know what you are doing here, but lets pretend you are reading a data file
# that is named by dataset
filedata <- read.table(dataset, header=T)
return(filedata)
}
雷夫
答案 4 :(得分:1)
仅供参考,这是一个避免副作用的完整样本玩具解决方案:
outerfunc <- function(names) {
templist <- list()
for (aname in names) {
templist[[aname]] <- innerfunc(aname)
}
templist
}
innerfunc <- function(aname) {
retval <- NULL
if ("one" %in% aname) retval <- c(1)
if ("two" %in% aname) retval <- c(1,2)
if ("three" %in% aname) retval <- c(1,2,3)
retval
}
names <- c("one","two","three")
name_vals <- outerfunc(names)
for (name in names) assign(name, name_vals[[name]])
答案 5 :(得分:0)
第三种方法:内部函数返回对大数组的引用,然后循环中的下一个语句解除引用并存储在需要它的任何地方(理想情况下使用单个指针存储而不必记忆整个数组)。
这消除了副作用和大数据结构的传递。
答案 6 :(得分:-1)
如果不知道使用的语言/编译器,很难肯定地说。但是,如果您只是将指针/引用传递给您正在创建的对象,那么对象本身的大小与函数调用的速度无关。在未来操纵这些数据可能是另一回事。