Хуже греха: побочные эффекты или пролет массивных предметов?

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

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

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

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

Я рекомендую отредактировать этот пост, включив в него краткий псевдокод, чтобы было легче увидеть, что вы пытаетесь сделать.

Jeff Atwood 17.09.2008 07:52

Да, пожалуйста, добавьте псевдокод, невозможно понять, что вы имеете в виду. Когда вы говорите «обработать ... и сохранить результат», вы имеете в виду «сохранить одну и ту же строку» или вектор (целых чисел, ссылающихся на слова) или что? Вы храните его как запись в каком-то огромном фрейме данных / массиве / матрице? Дайте нам некоторое представление о количестве строк, столбцов, размеров файлов, фрагментов и векторов, а также о вашей рабочей памяти?

smci 28.04.2016 16:23
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
2
942
7

Ответы 7

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

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

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

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

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

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

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

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

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

Не уверен, что понимаю вопрос, но у меня есть несколько решений.

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

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

Другие вопросы по теме