2008-09-17 3 views
5

У меня есть функция внутри цикла внутри функции. Внутренняя функция приобретает и хранит большой вектор данных в памяти (в качестве глобальной переменной ... Я использую «R», который похож на «S-Plus»). Цикл проходит через длинный список данных, которые необходимо получить. Внешняя функция запускает процесс и переходит в список собираемых наборов данных.Хуже греха: побочные эффекты или прохождение массивных объектов?

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

Я запрограммировал внутренняя функция для хранения каждого набора данных, прежде чем перейти к следующему, поэтому все работы внешней функции происходит как побочные эффекты на глобальных переменных ... большой нет-нет. Является ли это лучше или хуже, чем сбор и возвращение гигантского вектора векторов векторов вектора памяти? Есть ли превосходный третий подход?

Будет ли изменен ответ, если я буду хранить векторы данных в базе данных, а не в памяти? В идеале, я хотел бы иметь возможность прекратить выполнение функции (или не выполнить ее из-за сетевых тайм-аутов), не теряя при этом всю информацию, обработанную до завершения.

+2

Я рекомендую редактировать этот пост, чтобы включить некоторые краткие псевдокод так легче увидеть, что вы пытаетесь сделать – 2008-09-17 03:52:45

+0

Да, пожалуйста, добавьте псевдокод , невозможно понять, что вы имеете в виду. Когда вы говорите «процесс ... и сохраняете результат», вы имеете в виду «хранить ту же самую строку» или вектор (из целых чисел, ссылки на слова) или что? Сохраняете ли вы его как запись в каком-то огромном массиве данных/матрице/матрице? Дайте нам некоторое представление о количестве строк, столбцов, файла, блоков и векторных размеров и вашей рабочей памяти? – smci 2016-04-28 13:23:48

ответ

-1

Трудно сказать окончательно, не зная используемый язык/компилятор. Однако, если вы можете просто передать указатель/ссылку на объект, который вы создаете, то размер самого объекта не имеет ничего общего со скоростью вызовов функций. Манипулирование этими данными по дороге может быть другой историей.

10

использовать переменные во внешней функции вместо глобальных переменных. Это дает вам лучшее из обоих подходов: вы не мутируете глобальное состояние, и вы не копируете большой объем данных. Если вам нужно выйти рано, просто верните частичные результаты.

(смотрите раздел «Scope» в руководстве R: http://cran.r-project.org/doc/manuals/R-intro.html#Scope)

0

Третий подход: внутренняя функция возвращает ссылку на большой массив, который затем разыменовывает и магазины, где это необходимо следующее заявление внутри цикла (в идеале с одним хранилищем указателей, а не с помощью memcopy всего массива).

Это устраняет как побочный эффект, так и прохождение больших структур данных.

4

Это не имеет большого значения для использования памяти, поэтому вы можете сделать код чистым.

Поскольку у R есть переменная-копия для переменных, изменение глобального объекта будет иметь такие же последствия для памяти, как передача чего-либо в возвращаемых значениях.

Если вы сохраняете выходы в базе данных (или даже в файле), у вас не будет проблем с использованием памяти, и данные будут поэтапно доступны по мере их создания, а не только в конце. Будь то быстрее с базой данных, зависит прежде всего от того, сколько памяти вы используете: это сокращение - сбор мусора, который будет оплачивать стоимость записи на диск.

В R есть как профилировщики времени, так и памяти, поэтому вы можете увидеть эмпирически, что такое удары.

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

Лейф

6

Вспомните Кнут. «Преждевременная оптимизация - это корень всего программирования зла».

Попробуйте побочный эффект бесплатной версии. Посмотрите, соответствует ли это вашим целям производительности. Если это так, отлично, у вас нет проблемы в первую очередь; если это не так, используйте побочные эффекты и запишите для следующего программиста, что ваша рука была вынуждена.

1

FYI, вот полный пример игрушка решение, которое позволяет избежать побочных эффектов:

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