У меня есть функция внутри цикла внутри функции. Внутренняя функция получает и сохраняет большой вектор данных в памяти (в качестве глобальной переменной ... Я использую «R», что похоже на «S-Plus»). Цикл перебирает длинный список данных, которые необходимо получить. Внешняя функция запускает процесс и передает список наборов данных, которые необходимо получить.
for (dataset in list_of_datasets) {
for (datachunk in dataset) {
<process datachunk>
<store result? as vector? where?>
}
}
Я запрограммировал внутреннюю функцию для хранения каждого набора данных перед переходом к следующему, поэтому вся работа внешней функции происходит как побочные эффекты для глобальных переменных ... большое "нет-нет". Это лучше или хуже, чем собирать и возвращать гигантский вектор векторов, требующий больших затрат памяти? Есть ли лучший третий подход?
Изменился бы ответ, если бы я хранил векторы данных в базе данных, а не в памяти? В идеале я хотел бы иметь возможность завершить функцию (или дать ей сбой из-за тайм-аутов сети) без потери всей информации, обработанной до завершения.
Да, пожалуйста, добавьте псевдокод, невозможно понять, что вы имеете в виду. Когда вы говорите «обработать ... и сохранить результат», вы имеете в виду «сохранить одну и ту же строку» или вектор (целых чисел, ссылающихся на слова) или что? Вы храните его как запись в каком-то огромном фрейме данных / массиве / матрице? Дайте нам некоторое представление о количестве строк, столбцов, размеров файлов, фрагментов и векторов, а также о вашей рабочей памяти?
Трудно сказать однозначно, не зная используемого языка / компилятора. Однако, если вы можете просто передать указатель / ссылку на объект, который вы создаете, тогда размер самого объекта не имеет ничего общего со скоростью вызовов функций. Другое дело - манипулирование этими данными в будущем.
используйте переменные во внешней функции вместо глобальных переменных. Это дает вам лучшее из обоих подходов: вы не изменяете глобальное состояние и не копируете большой объем данных. Если вам нужно выйти раньше, просто верните частичные результаты.
(См. Раздел «Область действия» в руководстве R: http://cran.r-project.org/doc/manuals/R-intro.html#Scope)
Третий подход: внутренняя функция возвращает ссылку на большой массив, который следующий оператор внутри цикла затем разыменовывает и сохраняет там, где это необходимо (в идеале с одним хранилищем указателя, а не путем копирования всего массива в память).
Это избавляет как от побочного эффекта, так и от передачи больших структур данных.
Это не повлияет на использование памяти, так что вы можете сделать код чистым.
Поскольку в R есть копирование при изменении для переменных, изменение глобального объекта будет иметь те же последствия для памяти, что и передача чего-либо в возвращаемых значениях.
Если вы сохраняете выходные данные в базе данных (или даже в файле), у вас не будет проблем с использованием памяти, и данные будут доступны постепенно по мере их создания, а не только в конце. Будет ли это быстрее с базой данных, зависит в первую очередь от того, сколько памяти вы используете: сокращение затрат на запись на диск оплачивается сборкой мусора.
В R есть профилировщики как времени, так и памяти, поэтому вы можете эмпирически увидеть, каковы будут последствия.
Не уверен, что понимаю вопрос, но у меня есть несколько решений.
Внутри функции создайте список векторов и верните его.
Внутри функции создайте среду и сохраните в ней все векторы. Только убедитесь, что вы вернули окружение в случае ошибок.
в 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)
}
Leif
Помните своего Кнута. «Преждевременная оптимизация - корень всего программного зла».
Попробуйте бесплатную версию с побочными эффектами. Посмотрите, соответствует ли это вашим целям производительности. Если это так, отлично, во-первых, у вас нет проблем; если нет, то используйте побочные эффекты и сделайте пометку следующему программисту, что ваша рука была вынуждена.
К вашему сведению, вот полный образец игрушечного раствора, который позволяет избежать побочных эффектов:
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]])
Я рекомендую отредактировать этот пост, включив в него краткий псевдокод, чтобы было легче увидеть, что вы пытаетесь сделать.