5

我在函数内部的循环中有一个函数。内部函数在内存中获取并存储大量数据向量(作为全局变量......我使用的是“R”,类似于“S-Plus”)。循环遍历要获取的一长串数据。外部函数启动该过程并传入要获取的数据集列表。

for (dataset in list_of_datasets) {
  for (datachunk in dataset) {
    <process datachunk>
    <store result? as vector? where?>
  }
}

我对内部函数进行了编程,以便在移动到下一个数据集之前存储每个数据集,因此外部函数的所有工作都会作为对全局变量的副作用发生......这是一个很大的禁忌。这比收集和返回一个巨大的、占用大量内存的向量是好还是坏?有没有更好的第三种方法?

如果我将数据向量存储在数据库中而不是内存中,答案会改变吗?理想情况下,我希望能够在不丢失终止之前处理的所有信息的情况下终止该功能(或使其因网络超时而失败)。

4

7 回答 7

9

在外部函数中使用变量而不是全局变量。这让您获得了两种方法的最佳效果:您不会改变全局状态,也不会复制大量数据。如果您必须提前退出,只需返回部分结果。

(请参阅 R 手册中的“范围”部分:http: //cran.r-project.org/doc/manuals/R-intro.html#Scope

于 2008-09-17T03:48:29.900 回答
6

记住你的 Knuth。“过早的优化是所有编程罪恶的根源。”

试试无副作用的版本。看看它是否符合您的绩效目标。如果是这样,那太好了,你一开始就没有问题。如果不是,则使用副作用,并为下一个程序员记下您的手是被迫的。

于 2008-09-17T04:11:08.660 回答
4

它不会对内存使用产生太大影响,因此您不妨使代码干净。

由于 R 对变量进行了修改时复制,因此修改全局对象将具有与在返回值中传递某些内容相同的内存含义。

如果您将输出存储在数据库中(甚至存储在文件中),您将不会遇到内存使用问题,并且数据将在创建时增量可用,而不仅仅是在最后。数据库是否更快主要取决于您使用了多少内存:减少垃圾收集是否会支付写入磁盘的成本。

R 中有时间和内存分析器,因此您可以凭经验看到影响是什么。

于 2008-09-17T03:51:30.190 回答
1

我不确定我是否理解这个问题,但我有几个解决方案。

  1. 在函数内部,创建一个向量列表并返回它。

  2. 在函数内部,创建一个环境并将所有向量存储在其中。只要确保在出现错误时返回环境即可。

在 R 中:

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)
}

莱夫

于 2008-09-17T03:58:26.367 回答
1

FYI, here's a full sample toy solution that avoids side effects:

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]])
于 2008-09-17T19:39:37.370 回答
0

第三种方法:内部函数返回对大数组的引用,然后循环内的下一条语句取消引用并将其存储在需要的任何位置(理想情况下使用单个指针存储,而不必 memcopy 整个数组)。

这消除了副作用和大型数据结构的传递。

于 2008-09-17T03:49:36.560 回答
-1

在不知道使用的语言/编译器的情况下很难明确地说出来。但是,如果您可以简单地将指针/引用传递给您正在创建的对象,那么对象本身的大小与函数调用的速度无关。在路上操纵这些数据可能是另一回事。

于 2008-09-17T03:43:22.923 回答